1 //####COPYRIGHTBEGIN####
3 // ----------------------------------------------------------------------------
4 // Copyright (C) 1998, 1999, 2000 Red Hat, Inc.
6 // This program is part of the eCos host tools.
8 // This program is free software; you can redistribute it and/or modify it
9 // under the terms of the GNU General Public License as published by the Free
10 // Software Foundation; either version 2 of the License, or (at your option)
13 // This program is distributed in the hope that it will be useful, but WITHOUT
14 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18 // You should have received a copy of the GNU General Public License along with
19 // this program; if not, write to the Free Software Foundation, Inc.,
20 // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 // ----------------------------------------------------------------------------
24 //####COPYRIGHTEND####
26 //#####DESCRIPTIONBEGIN####
28 //*************************************************************************
29 // BCMenu.cpp : implementation file
31 // Date : December 2, 1999
32 // Author : Brent Corkum
33 // Email : corkum@rocscience.com
34 // Latest Version : http://www.rocscience.com/~corkum/BCMenu.html
36 // Bug Fixes and portions of code supplied by:
38 // Ben Ashley,Girish Bharadwaj,Jean-Edouard Lachand-Robert,
39 // Robert Edward Caldecott,Kenny Goers,Leonardo Zide,
40 // Stefan Kuhr,Reiner Jung,Martin Vladic,Kim Yoo Chul,
43 // You are free to use/modify this code but leave this header intact.
44 // This class is public domain so you are free to use it any of
45 // your applications (Freeware,Shareware,Commercial). All I ask is
46 // that you let me know so that if you have a real winner I can
47 // brag to my buddies that some of my code is in your app. I also
48 // wouldn't mind if you sent me a copy of your application since I
49 // like to play with new stuff.
50 //*************************************************************************
51 //####DESCRIPTIONEND####
52 //==========================================================================
54 #include "stdafx.h" // Standard windows header file
55 #include "BCMenu.h" // BCMenu class declaration
56 #include <afxpriv.h> //SK: makes A2W and other spiffy AFX macros work
61 static char THIS_FILE[] = __FILE__;
66 #define OBM_CHECK 32760 // from winuser.h
70 #error This code does not work on Versions of MFC prior to 4.0
83 Win32Type IsShellType()
90 if(winVer<0x80000000){/*NT */
92 osvi= (OSVERSIONINFO *)malloc(sizeof(OSVERSIONINFO));
94 memset(osvi,0,sizeof(OSVERSIONINFO));
95 osvi->dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
97 if (osvi->dwMajorVersion>=4L)
98 ShellType=WinNT4orHigher;//yup, it is NT 4 or higher!
102 else if (LOBYTE(LOWORD(winVer))<4)
103 ShellType=Win32s;/*Win32s*/
105 ShellType=Windoze95;/*Windoze95*/
109 static Win32Type g_Shell=IsShellType();
111 void BCMenuData::SetAnsiString(LPCSTR szAnsiString)
114 SetWideString(A2W(szAnsiString)); //SK: see MFC Tech Note 059
117 CString BCMenuData::GetString(void)//returns the menu text in ANSI or UNICODE
118 //depending on the MFC-Version we are using
124 strText = m_szMenuText;
127 strText=W2A(m_szMenuText); //SK: see MFC Tech Note 059
133 CTypedPtrArray<CPtrArray, HMENU> BCMenu::m_AllSubMenus; // Stores list of all sub-menus
137 ===============================================================================
142 Constructor and Destructor.
144 ===============================================================================
149 m_bDynIcons = FALSE; // O.S. - no dynamic icons by default
150 disable_old_style=FALSE;
151 m_iconX = 16; // Icon sizes default to 16 x 16
154 m_unselectcheck = -1;
156 checkmapsshare=FALSE;
157 // set the color used for the transparent background in all bitmaps
158 m_bitmapBackground=RGB(192,192,192); //gray
159 m_bitmapBackgroundFlag=FALSE;
160 GetCPInfo(CP_ACP,&CPInfo);
169 BOOL BCMenu::IsNewShell ()
171 return (Windoze95==g_Shell || WinNT4orHigher==g_Shell);
175 BCMenuData::~BCMenuData()
180 delete[] m_szMenuText; //Need not check for NULL because ANSI X3J16 allows "delete NULL"
184 void BCMenuData::SetWideString(const wchar_t *szWideString)
186 delete[] m_szMenuText;//Need not check for NULL because ANSI X3J16 allows "delete NULL"
190 m_szMenuText = new wchar_t[sizeof(wchar_t)*(wcslen(szWideString)+1)];
192 wcscpy(m_szMenuText,szWideString);
195 m_szMenuText=NULL;//set to NULL so we need not bother about dangling non-NULL Ptrs
198 BOOL BCMenu::IsMenu(CMenu *submenu)
201 int numSubMenus = m_AllSubMenus.GetUpperBound();
202 for(m=0;m<=numSubMenus;++m){
203 if(submenu->m_hMenu==m_AllSubMenus[m])return(TRUE);
208 BOOL BCMenu::IsMenu(HMENU submenu)
211 int numSubMenus = m_AllSubMenus.GetUpperBound();
212 for(m=0;m<=numSubMenus;++m){
213 if(submenu==m_AllSubMenus[m])return(TRUE);
218 BOOL BCMenu::DestroyMenu()
220 // Destroy Sub menus:
222 int numAllSubMenus = m_AllSubMenus.GetUpperBound();
223 for(n = numAllSubMenus; n>= 0; n--){
224 if(m_AllSubMenus[n]==this->m_hMenu)m_AllSubMenus.RemoveAt(n);
226 int numSubMenus = m_SubMenus.GetUpperBound();
227 for(m = numSubMenus; m >= 0; m--){
228 numAllSubMenus = m_AllSubMenus.GetUpperBound();
229 for(n = numAllSubMenus; n>= 0; n--){
230 if(m_AllSubMenus[n]==m_SubMenus[m])m_AllSubMenus.RemoveAt(n);
232 delete((BCMenu *)FromHandle(m_SubMenus[m]));
234 m_SubMenus.RemoveAll();
236 int numItems = m_MenuList.GetUpperBound();
237 for(m = 0; m <= numItems; m++)delete(m_MenuList[m]);
238 m_MenuList.RemoveAll();
239 if(checkmaps&&!checkmapsshare){
243 // Call base-class implementation last:
244 return(CMenu::DestroyMenu());
248 ///////////////////////////////////////////////////////////////////////////
250 // BCMenu message handlers
254 ==========================================================================
255 void BCMenu::DrawItem(LPDRAWITEMSTRUCT)
256 ---------------------------------------
258 Called by the framework when a particular item needs to be drawn. We
259 overide this to draw the menu item in a custom-fashion, including icons
260 and the 3D rectangle bar.
261 ==========================================================================
265 void BCMenu::DrawItem (LPDRAWITEMSTRUCT lpDIS)
267 ASSERT(lpDIS != NULL);
268 CDC* pDC = CDC::FromHandle(lpDIS->hDC);
270 UINT state = (((BCMenuData*)(lpDIS->itemData))->nFlags);
271 if(state & MF_SEPARATOR){
272 rect.CopyRect(&lpDIS->rcItem);
273 rect.top+=rect.Height()>>1;
274 pDC->DrawEdge(&rect,EDGE_ETCHED,BF_TOP);
278 BOOL standardflag=FALSE,selectedflag=FALSE,disableflag=FALSE;
279 BOOL checkflag=FALSE;
280 COLORREF crText = GetSysColor(COLOR_MENUTEXT);
281 COLORREF m_clrBack=GetSysColor(COLOR_MENU);
282 CBrush m_brBackground,m_brSelect;
285 int nIconNormal=-1,xoffset=-1;
286 CImageList *bitmap=NULL;
290 // set some colors and the font
291 m_penBack.CreatePen (PS_SOLID,0,GetSysColor(COLOR_MENU));
292 m_brBackground.CreateSolidBrush(GetSysColor(COLOR_MENU));
293 m_brSelect.CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT));
294 ZeroMemory ((PVOID) &m_lf,sizeof (LOGFONT));
296 nm.cbSize = sizeof (NONCLIENTMETRICS);
297 VERIFY (SystemParametersInfo(SPI_GETNONCLIENTMETRICS,nm.cbSize,&nm,0));
298 m_lf = nm.lfMenuFont;
299 m_fontMenu.CreateFontIndirect (&m_lf);
301 // draw the colored rectangle portion
303 rect.CopyRect(&lpDIS->rcItem);
306 // draw the up/down/focused/disabled state
308 UINT state = lpDIS->itemState;
316 if(lpDIS->itemData != NULL){
317 nIconNormal = (((BCMenuData*)(lpDIS->itemData))->menuIconNormal);
318 xoffset = (((BCMenuData*)(lpDIS->itemData))->xoffset);
319 bitmap = (((BCMenuData*)(lpDIS->itemData))->bitmap);
320 strText = ((BCMenuData*) (lpDIS->itemData))->GetString();
322 if(state&ODS_CHECKED && nIconNormal<0){
323 if(state&ODS_SELECTED && m_selectcheck>0)checkflag=TRUE;
324 else if(m_unselectcheck>0) checkflag=TRUE;
326 else if(nIconNormal != -1){
328 if(state&ODS_SELECTED && !(state&ODS_GRAYED))selectedflag=TRUE;
329 else if(state&ODS_GRAYED) disableflag=TRUE;
336 if(state&ODS_SELECTED){ // draw the down edges
338 CPen *pOldPen = pDC->SelectObject (&m_penBack);
340 // You need only Text highlight and thats what you get
342 if(checkflag||standardflag||selectedflag||disableflag||state&ODS_CHECKED)
343 rect2.SetRect(rect.left+m_iconX+4+GAP,rect.top,rect.right,rect.bottom);
344 pDC->FillRect (rect2,&m_brSelect);
346 pDC->SelectObject (pOldPen);
347 if((HFONT)dispFont != NULL)dispFont.DeleteObject ();
348 dispFont.CreateFontIndirect (&lf);
349 crText = GetSysColor(COLOR_HIGHLIGHTTEXT);
352 CPen *pOldPen = pDC->SelectObject (&m_penBack);
353 pDC->FillRect (rect,&m_brBackground);
354 pDC->SelectObject (pOldPen);
358 pDC->Draw3dRect (rect,m_clrBack,m_clrBack);
359 if ((HFONT)dispFont != NULL) dispFont.DeleteObject ();
360 dispFont.CreateFontIndirect (&lf); //Normal
363 // draw the text if there is any
364 //We have to paint the text only if the image is nonexistant
366 dy = (rect.Height()-4-m_iconY)/2;
369 if(checkflag||standardflag||selectedflag||disableflag){
370 rect2.SetRect(rect.left+1,rect.top+1+dy,rect.left+m_iconX+3,
371 rect.top+m_iconY+3+dy);
372 pDC->Draw3dRect (rect2,m_clrBack,m_clrBack);
373 if(checkflag && checkmaps){
374 pDC->FillRect (rect2,&m_brBackground);
375 rect2.SetRect(rect.left,rect.top+dy,rect.left+m_iconX+4,
376 rect.top+m_iconY+4+dy);
378 pDC->Draw3dRect (rect2,m_clrBack,m_clrBack);
379 CPoint ptImage(rect.left+2,rect.top+2+dy);
381 if(state&ODS_SELECTED)checkmaps->Draw(pDC,1,ptImage,ILD_TRANSPARENT);
382 else checkmaps->Draw(pDC,0,ptImage,ILD_TRANSPARENT);
384 else if(disableflag){
386 CBitmap bitmapstandard;
387 GetBitmapFromImageList(pDC,bitmap,xoffset,bitmapstandard);
388 rect2.SetRect(rect.left,rect.top+dy,rect.left+m_iconX+4,
389 rect.top+m_iconY+4+dy);
390 pDC->Draw3dRect (rect2,m_clrBack,m_clrBack);
391 if(disable_old_style)
392 DitherBlt(lpDIS->hDC,rect.left+2,rect.top+2+dy,m_iconX,m_iconY,
393 (HBITMAP)(bitmapstandard),0,0);
395 DitherBlt2(pDC,rect.left+2,rect.top+2+dy,m_iconX,m_iconY,
397 bitmapstandard.DeleteObject();
400 else if(selectedflag){
401 pDC->FillRect (rect2,&m_brBackground);
402 rect2.SetRect(rect.left,rect.top+dy,rect.left+m_iconX+4,
403 rect.top+m_iconY+4+dy);
405 if(state&ODS_CHECKED)
406 pDC->Draw3dRect(rect2,GetSysColor(COLOR_3DSHADOW),
407 GetSysColor(COLOR_3DHILIGHT));
409 pDC->Draw3dRect(rect2,GetSysColor(COLOR_3DHILIGHT),
410 GetSysColor(COLOR_3DSHADOW));
412 CPoint ptImage(rect.left+2,rect.top+2+dy);
413 if(bitmap)bitmap->Draw(pDC,xoffset,ptImage,ILD_TRANSPARENT);
416 if(state&ODS_CHECKED){
418 COLORREF col =GetSysColor(COLOR_3DLIGHT);
419 brush.CreateSolidBrush(col);
420 pDC->FillRect(rect2,&brush);
421 brush.DeleteObject();
422 rect2.SetRect(rect.left,rect.top+dy,rect.left+m_iconX+4,
423 rect.top+m_iconY+4+dy);
425 pDC->Draw3dRect(rect2,GetSysColor(COLOR_3DSHADOW),
426 GetSysColor(COLOR_3DHILIGHT));
429 pDC->FillRect (rect2,&m_brBackground);
430 rect2.SetRect(rect.left,rect.top+dy,rect.left+m_iconX+4,
431 rect.top+m_iconY+4+dy);
432 pDC->Draw3dRect (rect2,m_clrBack,m_clrBack);
434 CPoint ptImage(rect.left+2,rect.top+2+dy);
435 if(bitmap)bitmap->Draw(pDC,xoffset,ptImage,ILD_TRANSPARENT);
438 if(nIconNormal<0 && state&ODS_CHECKED && !checkflag){
439 rect2.SetRect(rect.left+1,rect.top+2+dy,rect.left+m_iconX+1,
440 rect.top+m_iconY+2+dy);
442 info.fMask = MIIM_CHECKMARKS;
443 ::GetMenuItemInfo((HMENU)lpDIS->hwndItem,lpDIS->itemID,
444 MF_BYCOMMAND, &info);
445 if(state&ODS_CHECKED || info.hbmpUnchecked) {
446 Draw3DCheckmark(pDC, rect2, state&ODS_SELECTED,
447 state&ODS_CHECKED ? info.hbmpChecked :
452 //This is needed always so that we can have the space for check marks
454 x0=rect.left;y0=rect.top;
455 rect.left = rect.left + m_iconX + 8 + GAP;
457 if(!strText.IsEmpty()){
459 CRect rectt(rect.left,rect.top-1,rect.right,rect.bottom-1);
463 CString leftStr,rightStr;
464 leftStr.Empty();rightStr.Empty();
465 int tablocr=strText.ReverseFind(_T('\t'));
467 rightStr=strText.Mid(tablocr+1);
468 leftStr=strText.Left(strText.Find(_T('\t')));
469 rectt.right-=m_iconX;
471 else leftStr=strText;
473 int iOldMode = pDC->GetBkMode();
474 pDC->SetBkMode( TRANSPARENT);
476 // Draw the text in the correct colour:
478 UINT nFormat = DT_LEFT|DT_SINGLELINE|DT_VCENTER;
479 UINT nFormatr = DT_RIGHT|DT_SINGLELINE|DT_VCENTER;
480 if(!(lpDIS->itemState & ODS_GRAYED)){
481 pDC->SetTextColor(crText);
482 pDC->DrawText (leftStr,rectt,nFormat);
483 if(tablocr!=-1) pDC->DrawText (rightStr,rectt,nFormatr);
487 // Draw the disabled text
488 if(!(state & ODS_SELECTED)){
489 RECT offset = *rectt;
494 pDC->SetTextColor(GetSysColor(COLOR_BTNHILIGHT));
495 pDC->DrawText(leftStr,&offset, nFormat);
496 if(tablocr!=-1) pDC->DrawText (rightStr,&offset,nFormatr);
497 pDC->SetTextColor(GetSysColor(COLOR_GRAYTEXT));
498 pDC->DrawText(leftStr,rectt, nFormat);
499 if(tablocr!=-1) pDC->DrawText (rightStr,rectt,nFormatr);
502 // And the standard Grey text:
503 pDC->SetTextColor(m_clrBack);
504 pDC->DrawText(leftStr,rectt, nFormat);
505 if(tablocr!=-1) pDC->DrawText (rightStr,rectt,nFormatr);
508 pFont = pDC->SelectObject (&dispFont);
509 pDC->SetBkMode( iOldMode );
510 pDC->SelectObject (pFont); //set it to the old font
513 m_penBack.DeleteObject();
514 m_brBackground.DeleteObject();
515 m_fontMenu.DeleteObject();
516 m_brSelect.DeleteObject();
517 dispFont.DeleteObject ();
521 BOOL BCMenu::GetBitmapFromImageList(CDC* pDC,CImageList *imglist,int nIndex,CBitmap &bmp)
523 HICON hIcon = imglist->ExtractIcon(nIndex);
525 dc.CreateCompatibleDC(pDC);
526 bmp.CreateCompatibleBitmap(pDC,m_iconX,m_iconY);
527 CBitmap* pOldBmp = dc.SelectObject(&bmp);
529 brush.CreateSolidBrush(GetSysColor(COLOR_MENU));
541 dc.SelectObject( pOldBmp );
543 // the icon is not longer needed
549 ==========================================================================
550 void BCMenu::MeasureItem(LPMEASUREITEMSTRUCT)
551 ---------------------------------------------
553 Called by the framework when it wants to know what the width and height
554 of our item will be. To accomplish this we provide the width of the
555 icon plus the width of the menu text, and then the height of the icon.
557 ==========================================================================
560 void BCMenu::MeasureItem( LPMEASUREITEMSTRUCT lpMIS )
562 UINT state = (((BCMenuData*)(lpMIS->itemData))->nFlags);
563 if(state & MF_SEPARATOR){
564 lpMIS->itemWidth = 0;
565 lpMIS->itemHeight = GetSystemMetrics(SM_CYMENU)>>1;
570 ZeroMemory ((PVOID) &m_lf,sizeof (LOGFONT));
572 nm.cbSize = sizeof (NONCLIENTMETRICS);
573 VERIFY(SystemParametersInfo(SPI_GETNONCLIENTMETRICS,
575 m_lf = nm.lfMenuFont;
576 m_fontMenu.CreateFontIndirect (&m_lf);
578 // Obtain the width of the text:
579 CWnd *pWnd = AfxGetMainWnd(); // Get main window
580 CDC *pDC = pWnd->GetDC(); // Get device context
581 CFont* pFont=NULL; // Select menu font in...
584 pFont = pDC->SelectObject (&m_fontMenu);// Select menu font in...
586 //Get pointer to text SK
587 const wchar_t *lpstrText = ((BCMenuData*)(lpMIS->itemData))->GetWideString();//SK: we use const to prevent misuse
593 VERIFY(::GetTextExtentPoint32W(pDC->m_hDC,lpstrText,
594 wcslen(lpstrText),&size)); //SK should also work on 95
595 #ifndef UNICODE //can't be UNICODE for Win32s
596 else{//it's Win32suckx
598 rect.left=rect.top=0;
599 size.cy=DrawText(pDC->m_hDC,(LPCTSTR)lpstrText,
600 wcslen(lpstrText),&rect,
601 DT_SINGLELINE|DT_LEFT|DT_VCENTER|DT_CALCRECT);
602 //+3 makes at least three pixels space to the menu border
603 size.cx=rect.right-rect.left+3;
604 size.cx += 3*(size.cx/wcslen(lpstrText));
608 CSize t = CSize(size);
610 pDC->SelectObject (pFont); // Select old font in
611 AfxGetMainWnd()->ReleaseDC(pDC); // Release the DC
613 // Set width and height:
615 lpMIS->itemWidth = m_iconX + t.cx + m_iconX + GAP;
616 int temp = GetSystemMetrics(SM_CYMENU);
617 lpMIS->itemHeight = temp>m_iconY+4 ? temp : m_iconY+4;
618 m_fontMenu.DeleteObject();
622 void BCMenu::SetIconSize (int width, int height)
628 BOOL BCMenu::AppendODMenuA(LPCSTR lpstrText,UINT nFlags,UINT nID,
632 return AppendODMenuW(A2W(lpstrText),nFlags,nID,nIconNormal);//SK: See MFC Tech Note 059
636 BOOL BCMenu::AppendODMenuW(wchar_t *lpstrText,UINT nFlags,UINT nID,
639 // Add the MF_OWNERDRAW flag if not specified:
641 if(nFlags&MF_BYPOSITION)nFlags=MF_SEPARATOR|MF_OWNERDRAW|MF_BYPOSITION;
642 else nFlags=MF_SEPARATOR|MF_OWNERDRAW;
644 else if(!(nFlags & MF_OWNERDRAW))nFlags |= MF_OWNERDRAW;
646 if(nFlags & MF_POPUP){
647 m_AllSubMenus.Add((HMENU)nID);
648 m_SubMenus.Add((HMENU)nID);
651 BCMenuData *mdata = new BCMenuData;
652 m_MenuList.Add(mdata);
653 mdata->SetWideString(lpstrText); //SK: modified for dynamic allocation
655 mdata->menuIconNormal = nIconNormal;
659 LoadFromToolBar(nID,nIconNormal,mdata->xoffset);
660 if(mdata->bitmap)mdata->bitmap->DeleteImageList();
661 else mdata->bitmap=new(CImageList);
662 mdata->bitmap->Create(m_iconX,m_iconY,ILC_COLORDDB|ILC_MASK,1,1);
663 if(!AddBitmapToImageList(mdata->bitmap,nIconNormal)){
664 mdata->bitmap->DeleteImageList();
665 delete mdata->bitmap;
667 mdata->menuIconNormal = nIconNormal = -1;
671 mdata->nFlags = nFlags;
673 return(CMenu::AppendMenu(nFlags, nID, (LPCTSTR)mdata));
676 BOOL BCMenu::AppendODMenuA(LPCSTR lpstrText,UINT nFlags,UINT nID,
677 CImageList *il,int xoffset)
680 return AppendODMenuW(A2W(lpstrText),nFlags,nID,il,xoffset);
683 BOOL BCMenu::AppendODMenuW(wchar_t *lpstrText,UINT nFlags,UINT nID,
684 CImageList *il,int xoffset)
686 // Add the MF_OWNERDRAW flag if not specified:
688 if(nFlags&MF_BYPOSITION)nFlags=MF_SEPARATOR|MF_OWNERDRAW|MF_BYPOSITION;
689 else nFlags=MF_SEPARATOR|MF_OWNERDRAW;
691 else if(!(nFlags & MF_OWNERDRAW))nFlags |= MF_OWNERDRAW;
693 if(nFlags & MF_POPUP){
694 m_AllSubMenus.Add((HMENU)nID);
695 m_SubMenus.Add((HMENU)nID);
698 BCMenuData *mdata = new BCMenuData;
699 m_MenuList.Add(mdata);
700 mdata->SetWideString(lpstrText); //SK: modified for dynamic allocation
703 mdata->menuIconNormal = 0;
705 if(mdata->bitmap)mdata->bitmap->DeleteImageList();
706 else mdata->bitmap=new(CImageList);
707 ImageListDuplicate(il,xoffset,mdata->bitmap);
710 mdata->menuIconNormal = -1;
713 mdata->nFlags = nFlags;
715 return(CMenu::AppendMenu(nFlags, nID, (LPCTSTR)mdata));
718 BOOL BCMenu::InsertODMenuA(UINT nPosition,LPCSTR lpstrText,UINT nFlags,UINT nID,
722 return InsertODMenuW(nPosition,A2W(lpstrText),nFlags,nID,nIconNormal);
726 BOOL BCMenu::InsertODMenuW(UINT nPosition,wchar_t *lpstrText,UINT nFlags,UINT nID,
729 if(!(nFlags & MF_BYPOSITION)){
731 BCMenu* pMenu = FindMenuOption(nPosition,iPosition);
733 return(pMenu->InsertODMenuW(iPosition,lpstrText,nFlags|MF_BYPOSITION,nID,nIconNormal));
738 if(!nID)nFlags=MF_SEPARATOR|MF_OWNERDRAW|MF_BYPOSITION;
739 else if(!(nFlags & MF_OWNERDRAW))nFlags |= MF_OWNERDRAW;
741 if(nFlags & MF_POPUP){
742 m_AllSubMenus.Add((HMENU)nID);
743 m_SubMenus.InsertAt(nPosition,(HMENU)nID);
746 BCMenuData *mdata = new BCMenuData;
747 m_MenuList.InsertAt(nPosition,mdata);
748 mdata->SetWideString(lpstrText); //SK: modified for dynamic allocation
750 mdata->menuIconNormal = nIconNormal;
754 LoadFromToolBar(nID,nIconNormal,mdata->xoffset);
755 if(mdata->bitmap)mdata->bitmap->DeleteImageList();
756 else mdata->bitmap=new(CImageList);
757 mdata->bitmap->Create(m_iconX,m_iconY,ILC_COLORDDB|ILC_MASK,1,1);
758 if(!AddBitmapToImageList(mdata->bitmap,nIconNormal)){
759 mdata->bitmap->DeleteImageList();
760 delete mdata->bitmap;
762 mdata->menuIconNormal = nIconNormal = -1;
766 mdata->nFlags = nFlags;
768 return(CMenu::InsertMenu(nPosition,nFlags,nID,(LPCTSTR)mdata));
771 BOOL BCMenu::InsertODMenuA(UINT nPosition,LPCSTR lpstrText,UINT nFlags,UINT nID,
772 CImageList *il,int xoffset)
775 return InsertODMenuW(nPosition,A2W(lpstrText),nFlags,nID,il,xoffset);
778 BOOL BCMenu::InsertODMenuW(UINT nPosition,wchar_t *lpstrText,UINT nFlags,UINT nID,
779 CImageList *il,int xoffset)
781 if(!(nFlags & MF_BYPOSITION)){
783 BCMenu* pMenu = FindMenuOption(nPosition,iPosition);
785 return(pMenu->InsertODMenuW(iPosition,lpstrText,nFlags|MF_BYPOSITION,nID,il,xoffset));
790 if(!nID)nFlags=MF_SEPARATOR|MF_OWNERDRAW|MF_BYPOSITION;
791 else if(!(nFlags & MF_OWNERDRAW))nFlags |= MF_OWNERDRAW;
793 if(nFlags & MF_POPUP){
794 m_AllSubMenus.Add((HMENU)nID);
795 m_SubMenus.InsertAt(nPosition,(HMENU)nID);
798 BCMenuData *mdata = new BCMenuData;
799 m_MenuList.InsertAt(nPosition,mdata);
800 mdata->SetWideString(lpstrText); //SK: modified for dynamic allocation
803 mdata->menuIconNormal = 0;
805 if(mdata->bitmap)mdata->bitmap->DeleteImageList();
806 else mdata->bitmap=new(CImageList);
807 ImageListDuplicate(il,xoffset,mdata->bitmap);
810 mdata->menuIconNormal = -1;
813 mdata->nFlags = nFlags;
815 return(CMenu::InsertMenu(nPosition,nFlags,nID,(LPCTSTR)mdata));
818 BOOL BCMenu::ModifyODMenuA(const char * lpstrText,UINT nID,int nIconNormal)
821 return ModifyODMenuW(A2W(lpstrText),nID,nIconNormal);//SK: see MFC Tech Note 059
824 BOOL BCMenu::ModifyODMenuW(wchar_t *lpstrText,UINT nID,int nIconNormal)
829 // Find the old BCMenuData structure:
830 BCMenu *psubmenu = FindMenuOption(nID,nLoc);
831 if(psubmenu && nLoc>=0)mdata = psubmenu->m_MenuList[nLoc];
833 // Create a new BCMenuData structure:
834 mdata = new BCMenuData;
835 m_MenuList.Add(mdata);
840 mdata->SetWideString(lpstrText); //SK: modified for dynamic allocation
841 mdata->menuIconNormal = nIconNormal;
845 LoadFromToolBar(nID,nIconNormal,mdata->xoffset);
846 if(mdata->bitmap)mdata->bitmap->DeleteImageList();
847 else mdata->bitmap=new CImageList;
848 mdata->bitmap->Create(m_iconX,m_iconY,ILC_COLORDDB|ILC_MASK,1,1);
849 if(!AddBitmapToImageList(mdata->bitmap,nIconNormal)){
850 mdata->bitmap->DeleteImageList();
851 delete mdata->bitmap;
853 mdata->menuIconNormal = nIconNormal = -1;
857 mdata->nFlags = MF_BYCOMMAND | MF_OWNERDRAW;
859 return (CMenu::ModifyMenu(nID,mdata->nFlags,nID,(LPCTSTR)mdata));
862 BOOL BCMenu::ModifyODMenuA(const char * lpstrText,UINT nID,CImageList *il,int xoffset)
865 return ModifyODMenuW(A2W(lpstrText),nID,il,xoffset);
868 BOOL BCMenu::ModifyODMenuW(wchar_t *lpstrText,UINT nID,CImageList *il,int xoffset)
873 // Find the old BCMenuData structure:
874 BCMenu *psubmenu = FindMenuOption(nID,nLoc);
875 if(psubmenu && nLoc>=0)mdata = psubmenu->m_MenuList[nLoc];
877 // Create a new BCMenuData structure:
878 mdata = new BCMenuData;
879 m_MenuList.Add(mdata);
884 mdata->SetWideString(lpstrText); //SK: modified for dynamic allocation
886 mdata->menuIconNormal = 0;
888 if(mdata->bitmap)mdata->bitmap->DeleteImageList();
889 else mdata->bitmap=new(CImageList);
890 ImageListDuplicate(il,xoffset,mdata->bitmap);
893 mdata->menuIconNormal = -1;
896 mdata->nFlags = MF_BYCOMMAND | MF_OWNERDRAW;
898 return (CMenu::ModifyMenu(nID,mdata->nFlags,nID,(LPCTSTR)mdata));
901 BOOL BCMenu::ModifyODMenuA(const char * lpstrText,UINT nID,CBitmap *bmp)
904 return ModifyODMenuW(A2W(lpstrText),nID,bmp);
907 BOOL BCMenu::ModifyODMenuW(wchar_t *lpstrText,UINT nID,CBitmap *bmp)
911 temp.Create(m_iconX,m_iconY,ILC_COLORDDB|ILC_MASK,1,1);
912 if(m_bitmapBackgroundFlag)temp.Add(bmp,m_bitmapBackground);
913 else temp.Add(bmp,GetSysColor(COLOR_3DFACE));
914 return ModifyODMenuW(lpstrText,nID,&temp,0);
916 return ModifyODMenuW(lpstrText,nID,NULL,0);
920 BOOL BCMenu::ModifyODMenuA(const char *lpstrText,const char *OptionText,
924 return ModifyODMenuW(A2W(lpstrText),A2W(OptionText),nIconNormal);//SK: see MFC Tech Note 059
927 BOOL BCMenu::ModifyODMenuW(wchar_t *lpstrText,wchar_t *OptionText,
932 // Find the old BCMenuData structure:
933 CString junk=OptionText;
934 mdata=FindMenuOption(OptionText);
937 mdata->SetWideString(lpstrText);//SK: modified for dynamic allocation
938 mdata->menuIconNormal = nIconNormal;
942 if(mdata->bitmap)mdata->bitmap->DeleteImageList();
943 else mdata->bitmap=new(CImageList);
944 mdata->bitmap->Create(m_iconX,m_iconY,ILC_COLORDDB|ILC_MASK,1,1);
945 if(!AddBitmapToImageList(mdata->bitmap,nIconNormal)){
946 mdata->bitmap->DeleteImageList();
947 delete mdata->bitmap;
949 mdata->menuIconNormal = nIconNormal = -1;
958 BCMenuData *BCMenu::NewODMenu(UINT pos,UINT nFlags,UINT nID,CString string)
962 mdata = new BCMenuData;
963 mdata->menuIconNormal = -1;
966 mdata->SetWideString((LPCTSTR)string);//SK: modified for dynamic allocation
968 mdata->SetAnsiString(string);
970 mdata->nFlags = nFlags;
973 if(nFlags & MF_POPUP)m_AllSubMenus.Add((HMENU)nID);
975 if (nFlags&MF_OWNERDRAW){
976 ASSERT(!(nFlags&MF_STRING));
977 ModifyMenu(pos,nFlags,nID,(LPCTSTR)mdata);
979 else if (nFlags&MF_STRING){
980 ASSERT(!(nFlags&MF_OWNERDRAW));
981 ModifyMenu(pos,nFlags,nID,mdata->GetString());
984 ASSERT(nFlags&MF_SEPARATOR);
985 ModifyMenu(pos,nFlags,nID);
991 BOOL BCMenu::LoadToolbars(const UINT *arID,int n)
994 BOOL returnflag=TRUE;
995 for(int i=0;i<n;++i){
996 if(!LoadToolbar(arID[i]))returnflag=FALSE;
1001 BOOL BCMenu::LoadToolbar(UINT nToolBar)
1004 BOOL returnflag=FALSE;
1007 bar.Create(AfxGetMainWnd());
1008 if(bar.LoadToolBar(nToolBar)){
1009 for(int i=0;i<bar.GetCount();++i){
1010 nID = bar.GetItemID(i);
1011 if(nID && GetMenuState(nID, MF_BYCOMMAND)
1013 ModifyODMenu(NULL,nID,nToolBar);
1021 BOOL BCMenu::LoadFromToolBar(UINT nID,UINT nToolBar,int& xoffset)
1025 BOOL returnflag=FALSE;
1028 bar.Create(AfxGetMainWnd());
1029 if(bar.LoadToolBar(nToolBar)){
1030 offset=bar.CommandToIndex(nID);
1032 bar.GetButtonInfo(offset,nID,nStyle,xset);
1033 if(xset>0)xoffset=xset;
1041 BCMenuData *BCMenu::FindMenuItem(UINT nID)
1043 BCMenuData *pData = NULL;
1046 for(i = 0; i <= m_MenuList.GetUpperBound(); i++){
1047 if (m_MenuList[i]->nID == nID){
1048 pData = m_MenuList[i];
1054 BCMenu *pMenu = FindMenuOption(nID, loc);
1055 ASSERT(pMenu != this);
1057 return pMenu->FindMenuItem(nID);
1063 BCMenu *BCMenu::FindMenuOption(int nId,int& nLoc)
1066 BCMenu *psubmenu,*pgoodmenu;
1068 for(i=0;i<(int)(GetMenuItemCount());++i){
1070 psubmenu=dynamic_cast<BCMenu *>(GetSubMenu(i));
1072 psubmenu=(BCMenu *)GetSubMenu(i);
1075 pgoodmenu=psubmenu->FindMenuOption(nId,nLoc);
1076 if(pgoodmenu)return(pgoodmenu);
1078 else if(nId==(int)GetMenuItemID(i)){
1087 BCMenuData *BCMenu::FindMenuOption(wchar_t *lpstrText)
1091 BCMenuData *pmenulist;
1093 for(i=0;i<(int)(GetMenuItemCount());++i){
1095 psubmenu=dynamic_cast<BCMenu *>(GetSubMenu(i));
1097 psubmenu=(BCMenu *)GetSubMenu(i);
1100 pmenulist=psubmenu->FindMenuOption(lpstrText);
1101 if(pmenulist)return(pmenulist);
1104 const wchar_t *szWide;//SK: we use const to prevent misuse of this Ptr
1105 for(j=0;j<=m_MenuList.GetUpperBound();++j){
1106 szWide = m_MenuList[j]->GetWideString ();
1107 if(szWide && !wcscmp(lpstrText,szWide))//SK: modified for dynamic allocation
1108 return(m_MenuList[j]);
1116 BOOL BCMenu::LoadMenu(int nResource)
1118 return(BCMenu::LoadMenu(MAKEINTRESOURCE(nResource)));
1121 BOOL BCMenu::LoadMenu(LPCTSTR lpszResourceName)
1124 "IMPORTANT:Use BCMenu::DestroyMenu to destroy Loaded Menu's\n"));
1126 ASSERT(lpszResourceName != NULL);
1128 // Find the Menu Resource:
1129 HINSTANCE m_hInst = AfxFindResourceHandle(lpszResourceName,RT_MENU);
1130 HRSRC hRsrc = ::FindResource(m_hInst,lpszResourceName,RT_MENU);
1131 if(hRsrc == NULL)return FALSE;
1133 // Load the Menu Resource:
1135 HGLOBAL hGlobal = LoadResource(m_hInst, hRsrc);
1136 if(hGlobal == NULL)return FALSE;
1138 // Attempt to create us as a menu...
1140 if(!CMenu::CreateMenu())return FALSE;
1142 // Get Item template Header, and calculate offset of MENUITEMTEMPLATES
1144 MENUITEMTEMPLATEHEADER *pTpHdr=
1145 (MENUITEMTEMPLATEHEADER*)LockResource(hGlobal);
1146 BYTE* pTp=(BYTE*)pTpHdr +
1147 (sizeof(MENUITEMTEMPLATEHEADER) + pTpHdr->offset);
1150 // Variables needed during processing of Menu Item Templates:
1153 WORD dwFlags = 0; // Flags of the Menu Item
1154 WORD dwID = 0; // ID of the Menu Item
1155 UINT uFlags; // Actual Flags.
1156 wchar_t *szCaption=NULL;
1157 int nLen = 0; // Length of caption
1158 CTypedPtrArray<CPtrArray, BCMenu*> m_Stack; // Popup menu stack
1159 CArray<BOOL,BOOL> m_StackEnd; // Popup menu stack
1160 m_Stack.Add(this); // Add it to this...
1161 m_StackEnd.Add(FALSE);
1164 // Obtain Flags and (if necessary), the ID...
1165 memcpy(&dwFlags, pTp, sizeof(WORD));pTp+=sizeof(WORD);// Obtain Flags
1166 if(!(dwFlags & MF_POPUP)){
1167 memcpy(&dwID, pTp, sizeof(WORD)); // Obtain ID
1172 uFlags = (UINT)dwFlags; // Remove MF_END from the flags that will
1173 if(uFlags & MF_END) // be passed to the Append(OD)Menu functions.
1176 // Obtain Caption (and length)
1179 szCaption=new wchar_t[wcslen((wchar_t *)pTp)+1];
1180 wcscpy(szCaption,(wchar_t *)pTp);
1181 pTp=&pTp[(wcslen((wchar_t *)pTp)+1)*sizeof(wchar_t)];//modified SK
1183 // Handle popup menus first....
1185 //WideCharToMultiByte
1186 if(dwFlags & MF_POPUP){
1187 if(dwFlags & MF_END)m_StackEnd.SetAt(m_Stack.GetUpperBound(),TRUE);
1188 BCMenu* pSubMenu = new BCMenu;
1189 pSubMenu->m_unselectcheck=m_unselectcheck;
1190 pSubMenu->m_selectcheck=m_selectcheck;
1191 pSubMenu->checkmaps=checkmaps;
1192 pSubMenu->checkmapsshare=TRUE;
1193 pSubMenu->CreatePopupMenu();
1195 // Append it to the top of the stack:
1197 m_Stack[m_Stack.GetUpperBound()]->AppendODMenuW(szCaption,uFlags,
1198 (UINT)pSubMenu->m_hMenu, -1);
1199 m_Stack.Add(pSubMenu);
1200 m_StackEnd.Add(FALSE);
1203 m_Stack[m_Stack.GetUpperBound()]->AppendODMenuW(szCaption, uFlags,
1205 if(dwFlags & MF_END)m_StackEnd.SetAt(m_Stack.GetUpperBound(),TRUE);
1206 j = m_Stack.GetUpperBound();
1207 while(j>=0 && m_StackEnd.GetAt(j)){
1208 m_Stack[m_Stack.GetUpperBound()]->InsertSpaces();
1209 m_Stack.RemoveAt(j);
1210 m_StackEnd.RemoveAt(j);
1216 }while(m_Stack.GetUpperBound() != -1);
1218 for(int i=0;i<(int)GetMenuItemCount();++i){
1219 CString str=m_MenuList[i]->GetString();
1222 m_MenuList[i]->nFlags=MF_POPUP|MF_BYPOSITION;
1223 ModifyMenu(i,MF_POPUP|MF_BYPOSITION,
1224 (UINT)GetSubMenu(i)->m_hMenu,str);
1227 m_MenuList[i]->nFlags=MF_STRING|MF_BYPOSITION;
1228 ModifyMenu(i,MF_STRING|MF_BYPOSITION,m_MenuList[i]->nID,str);
1235 void BCMenu::InsertSpaces(void)
1237 int i,j,numitems,maxlength;
1238 CString string,newstring;
1243 ZeroMemory ((PVOID) &m_lf,sizeof (LOGFONT));
1244 NONCLIENTMETRICS nm;
1245 nm.cbSize = sizeof (NONCLIENTMETRICS);
1246 VERIFY (SystemParametersInfo (SPI_GETNONCLIENTMETRICS,nm.cbSize,&nm,0));
1247 m_lf = nm.lfMenuFont;
1248 m_fontMenu.CreateFontIndirect (&m_lf);
1250 CWnd *pWnd = AfxGetMainWnd();
1251 CDC *pDC = pWnd->GetDC();
1252 CFont* pFont = pDC->SelectObject (&m_fontMenu);
1254 numitems=GetMenuItemCount();
1256 for(i=0;i<numitems;++i){
1257 string=m_MenuList[i]->GetString();
1258 j=string.Find((char)9);
1260 if(j!=-1)newstring=string.Left(j);
1261 else newstring=string;
1262 newstring+=_T(" ");//SK: modified for Unicode correctness.
1263 LPCTSTR lpstrText = (LPCTSTR)newstring;
1264 t=pDC->GetTextExtent(lpstrText,_tcslen(lpstrText));
1265 if(t.cx>maxlength)maxlength = t.cx;
1267 for(i=0;i<numitems;++i){
1268 string=m_MenuList[i]->GetString();
1269 j=string.Find((char)9);
1272 newstring=string.Left(j);
1273 LPCTSTR lpstrText = (LPCTSTR)(newstring);
1274 t=pDC->GetTextExtent(lpstrText,_tcslen(lpstrText));
1275 while(t.cx<maxlength){
1276 newstring+=_T(' ');//SK: modified for Unicode correctness
1277 LPCTSTR lpstrText = (LPCTSTR)(newstring);
1278 t=pDC->GetTextExtent(lpstrText,_tcslen(lpstrText));
1280 newstring+=string.Mid(j);
1282 m_MenuList[i]->SetWideString(newstring);//SK: modified for dynamic allocation
1284 m_MenuList[i]->SetAnsiString(newstring);
1288 pDC->SelectObject (pFont); // Select old font in
1289 AfxGetMainWnd()->ReleaseDC(pDC); // Release the DC
1290 m_fontMenu.DeleteObject();
1293 void BCMenu::LoadCheckmarkBitmap(int unselect, int select)
1295 if(unselect>0 && select>0){
1296 m_selectcheck=select;
1297 m_unselectcheck=unselect;
1298 if(checkmaps)checkmaps->DeleteImageList();
1299 else checkmaps=new(CImageList);
1300 checkmaps->Create(m_iconX,m_iconY,ILC_MASK,2,1);
1301 BOOL flag1=AddBitmapToImageList(checkmaps,unselect);
1302 BOOL flag2=AddBitmapToImageList(checkmaps,select);
1304 checkmaps->DeleteImageList();
1311 //--------------------------------------------------------------------------
1313 BOOL BCMenu::GetMenuText(UINT id, CString& string, UINT nFlags/*= MF_BYPOSITION*/)
1315 BOOL returnflag=FALSE;
1317 if(MF_BYPOSITION&nFlags){
1318 UINT numMenuItems = m_MenuList.GetUpperBound();
1319 if(id<=numMenuItems){
1320 string=m_MenuList[id]->GetString();
1326 BCMenu* pMenu = FindMenuOption(id,uiLoc);
1327 if(NULL!=pMenu) returnflag = pMenu->GetMenuText(uiLoc,string);
1333 void BCMenu::DrawRadioDot(CDC *pDC,int x,int y,COLORREF color)
1335 CRect rcDot(x,y,x+6,y+6);
1338 brush.CreateSolidBrush(color);
1339 pen.CreatePen(PS_SOLID,0,color);
1340 CBrush *pOldBrush=pDC->SelectObject(&brush);
1341 CPen *pOldPen=pDC->SelectObject(&pen);
1342 pDC->Ellipse(&rcDot);
1343 pDC->SelectObject(pOldBrush);
1344 pDC->SelectObject(pOldPen);
1346 brush.DeleteObject();
1349 void BCMenu::DrawCheckMark(CDC* pDC,int x,int y,COLORREF color)
1351 pDC->SetPixel(x,y+2,color);
1352 pDC->SetPixel(x,y+3,color);
1353 pDC->SetPixel(x,y+4,color);
1355 pDC->SetPixel(x+1,y+3,color);
1356 pDC->SetPixel(x+1,y+4,color);
1357 pDC->SetPixel(x+1,y+5,color);
1359 pDC->SetPixel(x+2,y+4,color);
1360 pDC->SetPixel(x+2,y+5,color);
1361 pDC->SetPixel(x+2,y+6,color);
1363 pDC->SetPixel(x+3,y+3,color);
1364 pDC->SetPixel(x+3,y+4,color);
1365 pDC->SetPixel(x+3,y+5,color);
1367 pDC->SetPixel(x+4,y+2,color);
1368 pDC->SetPixel(x+4,y+3,color);
1369 pDC->SetPixel(x+4,y+4,color);
1371 pDC->SetPixel(x+5,y+1,color);
1372 pDC->SetPixel(x+5,y+2,color);
1373 pDC->SetPixel(x+5,y+3,color);
1375 pDC->SetPixel(x+6,y,color);
1376 pDC->SetPixel(x+6,y+1,color);
1377 pDC->SetPixel(x+6,y+2,color);
1380 BCMenuData *BCMenu::FindMenuList(UINT nID)
1382 for(int i=0;i<=m_MenuList.GetUpperBound();++i){
1383 if(m_MenuList[i]->nID==nID && !m_MenuList[i]->syncflag){
1384 m_MenuList[i]->syncflag=1;
1385 return(m_MenuList[i]);
1391 void BCMenu::InitializeMenuList(int value)
1393 for(int i=0;i<=m_MenuList.GetUpperBound();++i)
1394 m_MenuList[i]->syncflag=value;
1397 void BCMenu::DeleteMenuList(void)
1399 for(int i=0;i<=m_MenuList.GetUpperBound();++i){
1400 if(!m_MenuList[i]->syncflag){
1401 delete m_MenuList[i];
1406 void BCMenu::SynchronizeMenu(void)
1408 CTypedPtrArray<CPtrArray, BCMenuData*> temp;
1411 UINT submenu,nID=0,state,j;
1413 InitializeMenuList(0);
1414 for(j=0;j<GetMenuItemCount();++j){
1416 state=GetMenuState(j,MF_BYPOSITION);
1418 submenu=(UINT)GetSubMenu(j)->m_hMenu;
1419 mdata=FindMenuList(submenu);
1420 GetMenuString(j,string,MF_BYPOSITION);
1421 if(!mdata)mdata=NewODMenu(j,
1422 (state&0xFF)|MF_BYPOSITION|MF_POPUP|MF_OWNERDRAW,submenu,string);
1423 else if(string.GetLength()>0)
1425 mdata->SetWideString(string); //SK: modified for dynamic allocation
1427 mdata->SetAnsiString(string);
1430 else if(state&MF_SEPARATOR){
1431 mdata=FindMenuList(0);
1432 if(!mdata)mdata=NewODMenu(j,
1433 state|MF_BYPOSITION|MF_SEPARATOR|MF_OWNERDRAW,0,_T(""));//SK: modified for Unicode correctness
1434 else ModifyMenu(j,mdata->nFlags,nID,(LPCTSTR)mdata);
1437 nID=GetMenuItemID(j);
1438 mdata=FindMenuList(nID);
1439 GetMenuString(j,string,MF_BYPOSITION);
1440 if(!mdata)mdata=NewODMenu(j,state|MF_BYPOSITION|MF_OWNERDRAW,
1443 mdata->nFlags=state|MF_BYPOSITION|MF_OWNERDRAW;
1444 if(string.GetLength()>0)
1446 mdata->SetWideString(string);//SK: modified for dynamic allocation
1448 mdata->SetAnsiString(string);
1451 ModifyMenu(j,mdata->nFlags,nID,(LPCTSTR)mdata);
1454 if(mdata)temp.Add(mdata);
1457 m_MenuList.RemoveAll();
1458 m_MenuList.Append(temp);
1462 void BCMenu::UpdateMenu(CMenu *pmenu)
1465 BCMenu *psubmenu = dynamic_cast<BCMenu *>(pmenu);
1467 BCMenu *psubmenu = (BCMenu *)pmenu;
1469 if(psubmenu)psubmenu->SynchronizeMenu();
1472 LRESULT BCMenu::FindKeyboardShortcut(UINT nChar, UINT nFlags,
1476 BCMenu *pBCMenu = dynamic_cast<BCMenu *>(pMenu);
1478 BCMenu *pBCMenu = (BCMenu *)pMenu;
1480 if(pBCMenu && nFlags&MF_POPUP){
1481 CString key(_T('&'),2);//SK: modified for Unicode correctness
1482 key.SetAt(1,(TCHAR)nChar);
1485 int menusize = (int)pBCMenu->GetMenuItemCount();
1486 if(menusize!=(pBCMenu->m_MenuList.GetUpperBound()+1))
1487 pBCMenu->SynchronizeMenu();
1488 for(int i=0;i<menusize;++i){
1489 if(pBCMenu->GetMenuText(i,menutext)){
1490 menutext.MakeLower();
1491 if(menutext.Find(key)>=0)return(MAKELRESULT(i,2));
1498 void BCMenu::DitherBlt (HDC hdcDest, int nXDest, int nYDest, int nWidth,
1499 int nHeight, HBITMAP hbm, int nXSrc, int nYSrc)
1501 ASSERT(hdcDest && hbm);
1502 ASSERT(nWidth > 0 && nHeight > 0);
1504 // Create a generic DC for all BitBlts
1505 HDC hDC = CreateCompatibleDC(hdcDest);
1510 // Create a DC for the monochrome DIB section
1511 HDC bwDC = CreateCompatibleDC(hDC);
1516 // Create the monochrome DIB section with a black and white palette
1518 BITMAPINFOHEADER bmiHeader;
1519 RGBQUAD bmiColors[2];
1520 } RGBBWBITMAPINFO = {
1522 { // a BITMAPINFOHEADER
1523 sizeof(BITMAPINFOHEADER), // biSize
1525 nHeight, // biHeight;
1528 BI_RGB, // biCompression;
1530 0, // biXPelsPerMeter;
1531 0, // biYPelsPerMeter;
1533 0 // biClrImportant;
1536 { 0x00, 0x00, 0x00, 0x00 }, { 0xFF, 0xFF, 0xFF, 0x00 }
1540 HBITMAP hbmBW = CreateDIBSection(bwDC,
1541 (LPBITMAPINFO)&RGBBWBITMAPINFO, DIB_RGB_COLORS, &pbitsBW, NULL, 0);
1546 // Attach the monochrome DIB section and the bitmap to the DCs
1547 HBITMAP olddib = (HBITMAP)SelectObject(bwDC, hbmBW);
1548 HBITMAP hdcolddib = (HBITMAP)SelectObject(hDC, hbm);
1550 // BitBlt the bitmap into the monochrome DIB section
1551 BitBlt(bwDC, 0, 0, nWidth, nHeight, hDC, nXSrc, nYSrc, SRCCOPY);
1553 // Paint the destination rectangle in gray
1554 FillRect(hdcDest, CRect(nXDest, nYDest, nXDest + nWidth, nYDest +
1555 nHeight), GetSysColorBrush((IsNewShell())?COLOR_3DFACE:COLOR_MENU));
1556 //SK: looks better on the old shell
1557 // BitBlt the black bits in the monochrome bitmap into COLOR_3DHILIGHT
1558 // bits in the destination DC
1559 // The magic ROP comes from the Charles Petzold's book
1560 HBRUSH hb = CreateSolidBrush(GetSysColor(COLOR_3DHILIGHT));
1561 HBRUSH oldBrush = (HBRUSH)SelectObject(hdcDest, hb);
1562 BitBlt(hdcDest,nXDest+1,nYDest+1,nWidth,nHeight,bwDC,0,0,0xB8074A);
1564 // BitBlt the black bits in the monochrome bitmap into COLOR_3DSHADOW
1565 // bits in the destination DC
1566 hb = CreateSolidBrush(GetSysColor(COLOR_3DSHADOW));
1567 DeleteObject(SelectObject(hdcDest, hb));
1568 BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight,bwDC,0,0,0xB8074A);
1569 DeleteObject(SelectObject(hdcDest, oldBrush));
1570 VERIFY(DeleteObject(SelectObject(bwDC, olddib)));
1571 SelectObject(hDC, hdcolddib);
1574 VERIFY(DeleteDC(bwDC));
1577 VERIFY(DeleteDC(hDC));
1581 BOOL BCMenu::AddBitmapToImageList(CImageList *bmplist,UINT nResourceID)
1585 bmplist->Add((HICON)nResourceID);
1591 HBITMAP hbmp=LoadSysColorBitmap(nResourceID);
1595 if(m_bitmapBackgroundFlag) bmplist->Add(&bmp,m_bitmapBackground);
1596 else bmplist->Add(&bmp,GetSysColor(COLOR_3DFACE));
1601 else bReturn = FALSE;
1605 void BCMenu::SetBitmapBackground(COLORREF color)
1607 m_bitmapBackground=color;
1608 m_bitmapBackgroundFlag=TRUE;
1611 void BCMenu::UnSetBitmapBackground(void)
1613 m_bitmapBackgroundFlag=FALSE;
1616 // Given a toolbar, append all the options from it to this menu
1617 // Passed a ptr to the toolbar object and the toolbar ID
1618 // Author : Robert Edward Caldecott
1619 void BCMenu::AddFromToolBar(CToolBar* pToolBar, int nResourceID)
1621 for (int i = 0; i < pToolBar->GetCount(); i++) {
1622 UINT nID = pToolBar->GetItemID(i);
1623 // See if this toolbar option
1624 // appears as a command on this
1625 // menu or is a separator
1626 if (nID == 0 || GetMenuState(nID, MF_BYCOMMAND) == 0xFFFFFFFF)
1627 continue; // Item doesn't exist
1630 // Get the toolbar button info
1631 pToolBar->GetButtonInfo(i, nID, nStyle, nImage);
1632 // OK, we have the command ID of the toolbar
1633 // option, and the tollbar bitmap offset
1636 BCMenu *pSubMenu = FindMenuOption(nID, nLoc);
1637 if (pSubMenu && nLoc >= 0)pData = pSubMenu->m_MenuList[nLoc];
1639 // Create a new BCMenuData structure
1640 pData = new BCMenuData;
1641 m_MenuList.Add(pData);
1643 // Set some default structure members
1644 pData->menuIconNormal = nResourceID;
1646 pData->nFlags = MF_BYCOMMAND | MF_OWNERDRAW;
1647 pData->xoffset = nImage;
1648 if (pData->bitmap)pData->bitmap->DeleteImageList();
1649 else pData->bitmap = new CImageList;
1650 pData->bitmap->Create(m_iconX, m_iconY,ILC_COLORDDB|ILC_MASK, 1, 1);
1652 if(!AddBitmapToImageList(pData->bitmap, nResourceID)){
1653 pData->bitmap->DeleteImageList();
1654 delete pData->bitmap;
1656 pData->menuIconNormal = -1;
1657 pData->xoffset = -1;
1661 ModifyMenu(nID,pData->nFlags,nID,(LPCTSTR)pData);
1665 BOOL BCMenu::Draw3DCheckmark(CDC *dc, const CRect& rc,
1666 BOOL bSelected, HBITMAP hbmCheck)
1670 COLORREF col=GetSysColor((bSelected||!IsNewShell())?COLOR_MENU:COLOR_3DLIGHT);//SK: Looks better on the old shell
1671 brush.CreateSolidBrush(col);
1672 dc->FillRect(rcDest,&brush);
1673 brush.DeleteObject();
1674 if (IsNewShell()) //SK: looks better on the old shell
1675 dc->DrawEdge(&rcDest, BDR_SUNKENOUTER, BF_RECT);
1676 if (!hbmCheck)DrawCheckMark(dc,rc.left+4,rc.top+4,GetSysColor(COLOR_MENUTEXT));
1677 else DrawRadioDot(dc,rc.left+5,rc.top+4,GetSysColor(COLOR_MENUTEXT));
1681 void BCMenu::DitherBlt2(CDC *drawdc, int nXDest, int nYDest, int nWidth,
1682 int nHeight, CBitmap &bmp, int nXSrc, int nYSrc)
1684 // create a monochrome memory DC
1686 ddc.CreateCompatibleDC(0);
1688 bwbmp.CreateCompatibleBitmap(&ddc, nWidth, nHeight);
1689 CBitmap * pddcOldBmp = ddc.SelectObject(&bwbmp);
1692 dc.CreateCompatibleDC(0);
1693 CBitmap * pdcOldBmp = dc.SelectObject(&bmp);
1696 ddc.PatBlt(0, 0, nWidth, nHeight, WHITENESS);
1697 dc.SetBkColor(GetSysColor(COLOR_BTNFACE));
1698 ddc.BitBlt(0, 0, nWidth, nHeight, &dc, nXSrc,nYSrc, SRCCOPY);
1699 dc.SetBkColor(GetSysColor(COLOR_BTNHILIGHT));
1700 ddc.BitBlt(0, 0, nWidth, nHeight, &dc, nXSrc,nYSrc, SRCPAINT);
1702 // Copy the image from the toolbar into the memory DC
1703 // and draw it (grayed) back into the toolbar.
1704 dc.FillSolidRect(0,0, nWidth, nHeight, GetSysColor((IsNewShell())?COLOR_3DFACE:COLOR_MENU));
1705 //SK: Looks better on the old shell
1706 dc.SetBkColor(RGB(0, 0, 0));
1707 dc.SetTextColor(RGB(255, 255, 255));
1708 CBrush brShadow, brHilight;
1709 brHilight.CreateSolidBrush(GetSysColor(COLOR_BTNHILIGHT));
1710 brShadow.CreateSolidBrush(GetSysColor(COLOR_BTNSHADOW));
1711 CBrush * pOldBrush = dc.SelectObject(&brHilight);
1712 dc.BitBlt(0,0, nWidth, nHeight, &ddc, 0, 0, 0x00E20746L);
1713 drawdc->BitBlt(nXDest+1,nYDest+1,nWidth, nHeight, &dc,0,0,SRCCOPY);
1714 dc.BitBlt(1,1, nWidth, nHeight, &ddc, 0, 0, 0x00E20746L);
1715 dc.SelectObject(&brShadow);
1716 dc.BitBlt(0,0, nWidth, nHeight, &ddc, 0, 0, 0x00E20746L);
1717 drawdc->BitBlt(nXDest,nYDest,nWidth, nHeight, &dc,0,0,SRCCOPY);
1719 ddc.SelectObject(pddcOldBmp);
1721 dc.SelectObject(pOldBrush);
1722 dc.SelectObject(pdcOldBmp);
1725 brShadow.DeleteObject();
1726 brHilight.DeleteObject();
1727 bwbmp.DeleteObject();
1730 void BCMenu::SetDisableOldStyle(void)
1732 disable_old_style=TRUE;
1735 void BCMenu::UnSetDisableOldStyle(void)
1737 disable_old_style=FALSE;
1740 BOOL BCMenu::GetDisableOldStyle(void)
1742 return(disable_old_style);
1746 HBITMAP BCMenu::LoadSysColorBitmap(int nResourceId)
1749 AfxFindResourceHandle(MAKEINTRESOURCE(nResourceId),RT_BITMAP);
1751 ::FindResource(hInst,MAKEINTRESOURCE(nResourceId),RT_BITMAP);
1754 return AfxLoadSysColorBitmap(hInst, hRsrc, FALSE);
1757 BOOL BCMenu::RemoveMenu(UINT uiId,UINT nFlags)
1759 if(MF_BYPOSITION&nFlags){
1760 UINT uint = GetMenuState(uiId,MF_BYPOSITION);
1761 if(uint&MF_SEPARATOR && !(uint&MF_POPUP)){
1762 delete m_MenuList.GetAt(uiId);
1763 m_MenuList.RemoveAt(uiId);
1766 BCMenu* pSubMenu = (BCMenu*) GetSubMenu(uiId);
1768 UINT uiCommandId = GetMenuItemID(uiId);
1769 for(int i=0;i<m_MenuList.GetSize(); i++){
1770 if(m_MenuList[i]->nID==uiCommandId){
1771 delete m_MenuList.GetAt(i);
1772 m_MenuList.RemoveAt(i);
1778 int numSubMenus = m_SubMenus.GetUpperBound();
1779 for(int m = numSubMenus; m >= 0; m--){
1780 if(m_SubMenus[m]==pSubMenu->m_hMenu){
1781 int numAllSubMenus = m_AllSubMenus.GetUpperBound();
1782 for(int n = numAllSubMenus; n>= 0; n--){
1783 if(m_AllSubMenus[n]==m_SubMenus[m])m_AllSubMenus.RemoveAt(n);
1785 m_SubMenus.RemoveAt(m);
1788 int num = pSubMenu->GetMenuItemCount();
1789 for(int i=num-1;i>=0;--i)pSubMenu->RemoveMenu(i,MF_BYPOSITION);
1790 for(i=m_MenuList.GetUpperBound();i>=0;i--){
1791 if(m_MenuList[i]->nID==(UINT)pSubMenu->m_hMenu){
1792 delete m_MenuList.GetAt(i);
1793 m_MenuList.RemoveAt(i);
1803 BCMenu* pMenu = FindMenuOption(uiId,iPosition);
1804 if(pMenu)pMenu->RemoveMenu(iPosition,MF_BYPOSITION);
1806 return CMenu::RemoveMenu(uiId,nFlags);
1809 BOOL BCMenu::DeleteMenu(UINT uiId,UINT nFlags)
1811 if(MF_BYPOSITION&nFlags){
1812 UINT uint = GetMenuState(uiId,MF_BYPOSITION);
1813 if(uint&MF_SEPARATOR && !(uint&MF_POPUP)){
1814 delete m_MenuList.GetAt(uiId);
1815 m_MenuList.RemoveAt(uiId);
1818 BCMenu* pSubMenu = (BCMenu*) GetSubMenu(uiId);
1820 UINT uiCommandId = GetMenuItemID(uiId);
1821 for(int i=0;i<m_MenuList.GetSize(); i++){
1822 if(m_MenuList[i]->nID==uiCommandId){
1823 delete m_MenuList.GetAt(i);
1824 m_MenuList.RemoveAt(i);
1830 int numSubMenus = m_SubMenus.GetUpperBound();
1831 for(int m = numSubMenus; m >= 0; m--){
1832 if(m_SubMenus[m]==pSubMenu->m_hMenu){
1833 int numAllSubMenus = m_AllSubMenus.GetUpperBound();
1834 for(int n = numAllSubMenus; n>= 0; n--){
1835 if(m_AllSubMenus[n]==m_SubMenus[m])m_AllSubMenus.RemoveAt(n);
1837 m_SubMenus.RemoveAt(m);
1840 int num = pSubMenu->GetMenuItemCount();
1841 for(int i=num-1;i>=0;--i)pSubMenu->DeleteMenu(i,MF_BYPOSITION);
1842 for(i=m_MenuList.GetUpperBound();i>=0;i--){
1843 if(m_MenuList[i]->nID==(UINT)pSubMenu->m_hMenu){
1844 delete m_MenuList.GetAt(i);
1845 m_MenuList.RemoveAt(i);
1855 BCMenu* pMenu = FindMenuOption(uiId,iPosition);
1856 if(pMenu)pMenu->DeleteMenu(iPosition,MF_BYPOSITION);
1858 return CMenu::DeleteMenu(uiId,nFlags);
1862 BOOL BCMenu::AppendMenuA(UINT nFlags,UINT nIDNewItem,const char *lpszNewItem,int nIconNormal)
1865 return AppendMenuW(nFlags,nIDNewItem,A2W(lpszNewItem),nIconNormal);
1868 BOOL BCMenu::AppendMenuW(UINT nFlags,UINT nIDNewItem,wchar_t *lpszNewItem,int nIconNormal)
1870 return AppendODMenuW(lpszNewItem,nFlags,nIDNewItem,nIconNormal);
1873 BOOL BCMenu::AppendMenuA(UINT nFlags,UINT nIDNewItem,const char *lpszNewItem,CImageList *il,int xoffset)
1876 return AppendMenuW(nFlags,nIDNewItem,A2W(lpszNewItem),il,xoffset);
1879 BOOL BCMenu::AppendMenuW(UINT nFlags,UINT nIDNewItem,wchar_t *lpszNewItem,CImageList *il,int xoffset)
1881 return AppendODMenuW(lpszNewItem,nFlags,nIDNewItem,il,xoffset);
1884 BOOL BCMenu::AppendMenuA(UINT nFlags,UINT nIDNewItem,const char *lpszNewItem,CBitmap *bmp)
1887 return AppendMenuW(nFlags,nIDNewItem,A2W(lpszNewItem),bmp);
1890 BOOL BCMenu::AppendMenuW(UINT nFlags,UINT nIDNewItem,wchar_t *lpszNewItem,CBitmap *bmp)
1894 temp.Create(m_iconX,m_iconY,ILC_COLORDDB|ILC_MASK,1,1);
1895 if(m_bitmapBackgroundFlag)temp.Add(bmp,m_bitmapBackground);
1896 else temp.Add(bmp,GetSysColor(COLOR_3DFACE));
1897 return AppendODMenuW(lpszNewItem,nFlags,nIDNewItem,&temp,0);
1899 return AppendODMenuW(lpszNewItem,nFlags,nIDNewItem,NULL,0);
1902 BOOL BCMenu::InsertMenuA(UINT nPosition,UINT nFlags,UINT nIDNewItem,const char *lpszNewItem,int nIconNormal)
1905 return InsertMenuW(nPosition,nFlags,nIDNewItem,A2W(lpszNewItem),nIconNormal);
1908 BOOL BCMenu::InsertMenuW(UINT nPosition,UINT nFlags,UINT nIDNewItem,wchar_t *lpszNewItem,int nIconNormal)
1910 return InsertODMenuW(nPosition,lpszNewItem,nFlags,nIDNewItem,nIconNormal);
1913 BOOL BCMenu::InsertMenuA(UINT nPosition,UINT nFlags,UINT nIDNewItem,const char *lpszNewItem,CImageList *il,int xoffset)
1916 return InsertMenuW(nPosition,nFlags,nIDNewItem,A2W(lpszNewItem),il,xoffset);
1919 BOOL BCMenu::InsertMenuW(UINT nPosition,UINT nFlags,UINT nIDNewItem,wchar_t *lpszNewItem,CImageList *il,int xoffset)
1921 return InsertODMenuW(nPosition,lpszNewItem,nFlags,nIDNewItem,il,xoffset);
1924 BOOL BCMenu::InsertMenuA(UINT nPosition,UINT nFlags,UINT nIDNewItem,const char *lpszNewItem,CBitmap *bmp)
1927 return InsertMenuW(nPosition,nFlags,nIDNewItem,A2W(lpszNewItem),bmp);
1930 BOOL BCMenu::InsertMenuW(UINT nPosition,UINT nFlags,UINT nIDNewItem,wchar_t *lpszNewItem,CBitmap *bmp)
1934 temp.Create(m_iconX,m_iconY,ILC_COLORDDB|ILC_MASK,1,1);
1935 if(m_bitmapBackgroundFlag)temp.Add(bmp,m_bitmapBackground);
1936 else temp.Add(bmp,GetSysColor(COLOR_3DFACE));
1937 return InsertODMenuW(nPosition,lpszNewItem,nFlags,nIDNewItem,&temp,0);
1939 return InsertODMenuW(nPosition,lpszNewItem,nFlags,nIDNewItem,NULL,0);
1942 //--------------------------------------------------------------------------
1944 BCMenu* BCMenu::AppendODPopupMenuW(wchar_t *lpstrText)
1946 BCMenu* pSubMenu = new BCMenu;
1947 pSubMenu->m_unselectcheck=m_unselectcheck;
1948 pSubMenu->m_selectcheck=m_selectcheck;
1949 pSubMenu->checkmaps=checkmaps;
1950 pSubMenu->checkmapsshare=TRUE;
1951 pSubMenu->CreatePopupMenu();
1952 AppendODMenuW(lpstrText,MF_POPUP,(UINT)pSubMenu->m_hMenu, -1);
1956 //--------------------------------------------------------------------------
1958 BCMenu* BCMenu::AppendODPopupMenuA(LPCSTR lpstrText)
1961 return AppendODPopupMenuW(A2W(lpstrText));
1964 BOOL BCMenu::ImageListDuplicate(CImageList *il,int xoffset,CImageList *newlist)
1966 if (il == NULL||newlist==NULL||xoffset<0) return FALSE;
1967 HICON hIcon = il->ExtractIcon(xoffset);
1969 ImageList_GetIconSize(il->m_hImageList, &cx, &cy);
1970 newlist->Create(cx,cy,ILC_COLOR32|ILC_MASK,1,1);
1971 newlist->Add(hIcon);
1972 ::DestroyIcon(hIcon);
1976 //*************************************************************************