// ==========================================================================
// Class Implementation : COXBitmapMenuOrganizer
// ==========================================================================
// Version: 9.3
// This software along with its related components, documentation and files ("The Libraries")
// is � 1994-2007 The Code Project (1612916 Ontario Limited) and use of The Libraries is
// governed by a software license agreement ("Agreement"). Copies of the Agreement are
// available at The Code Project (www.codeproject.com), as part of the package you downloaded
// to obtain this file, or directly from our office. For a copy of the license governing
// this software, you may contact us at legalaffairs@codeproject.com, or by calling 416-849-8900.
// //////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "OXBitmapMenuOrganizer.h"
#include "afxpriv.h"
#include "afxole.h"
#ifndef __OXMFCIMPL_H__
#if _MFC_VER >= 0x0700
#if _MFC_VER >= 1400
#include <afxtempl.h>
#endif
#include <..\src\mfc\afximpl.h>
#else
#include <..\src\afximpl.h>
#endif
#define __OXMFCIMPL_H__
#endif
#ifndef __OX_OLEIMPL2_H__
#ifdef MAP_LOGHIM_TO_PIX
#undef MAP_LOGHIM_TO_PIX
#endif
#ifdef MAP_PIX_TO_LOGHIM
#undef MAP_PIX_TO_LOGHIM
#endif
#if _MFC_VER < 0x0700
#include <..\src\oleimpl2.h>
#else
#include <..\src\mfc\oleimpl2.h>
#endif
#define __OX_OLEIMPL2_H__
#endif
#include "UTB64Bit.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#endif
#ifndef TB_GETIMAGELIST
#define TB_GETIMAGELIST (WM_USER + 49)
#endif // TB_GETIMAGELIST
#ifndef TB_GETHOTIMAGELIST
#define TB_GETHOTIMAGELIST (WM_USER + 53)
#endif // TB_GETHOTIMAGELIST
/////////////////////////////////////////////////////////////////////////////
// Definition of static members
// --- A map of all the frame windows that have been subclassed and that are associated with
// a menu organizer object. This object will handle the windows messages first
CMap<HWND, HWND, COXBitmapMenuOrganizer*, COXBitmapMenuOrganizer*>
COXBitmapMenuOrganizer::m_allMenuOrganizers;
// handle of the old mouse hook procedure
HHOOK COXBitmapMenuOrganizer::g_pfnOldMouseHookProc=NULL;
// handle of the old keyboard hook procedure
HHOOK COXBitmapMenuOrganizer::g_pfnOldKeyboardHookProc=NULL;
///////////////////////////////////////////
// Member functions ---------------------------------------------------------
// public:
COXBitmapMenuOrganizer::COXBitmapMenuOrganizer()
:
m_pFrameWnd(NULL),
m_hWnd(NULL),
m_pfnSuper(NULL),
m_bInCutomizationMode(FALSE),
m_hWndCustomizeOrganizer(NULL),
m_bShowOnlyRecentlyUsed(TRUE),
m_bForceToDisplayHiddenItems(FALSE),
m_bMainMenuIsActive(FALSE),
m_nActivePopupMenuCount(0),
m_pDeferedBM(NULL)
{
Init();
}
BOOL COXBitmapMenuOrganizer::Init(UINT cx, UINT cy, UINT nCheckID, UINT nBulletID)
{
CDC memDC;
VERIFY(memDC.CreateCompatibleDC(NULL));
CRect rcCheckMark;
ASSERT((!cx && !cy) || (cx && cy));
if(!cx && !cy)
{
rcCheckMark=CRect(0,0,
::GetSystemMetrics(SM_CXMENUCHECK),::GetSystemMetrics(SM_CYMENUCHECK));
// Convert from device to logical points
memDC.DPtoLP(&rcCheckMark);
}
else
{
rcCheckMark=CRect(0, 0, cx, cy);
}
if(m_DefaultImgList.m_hImageList!=NULL)
{
m_DefaultImgList.DeleteImageList();
}
// The default image list will contain a checkmark and a bulletmark
VERIFY(m_DefaultImgList.Create(rcCheckMark.right,rcCheckMark.bottom,TRUE,2,0));
CBitmap bmTemp;
VERIFY(bmTemp.CreateCompatibleBitmap(&memDC,rcCheckMark.right,rcCheckMark.bottom));
// Create a checkmark bitmap
ASSERT((nCheckID==NULL && nBulletID==NULL) || (nCheckID!=NULL && nCheckID!=NULL));
CBitmap* pbmTempOld;
if(!nCheckID)
{
pbmTempOld=memDC.SelectObject(&bmTemp);
memDC.DrawFrameControl(&rcCheckMark, DFC_MENU, DFCS_MENUCHECK);
memDC.SelectObject(pbmTempOld);
m_DefaultImgList.Add(&bmTemp, RGB(255,255,255));
}
else
{
CBitmap bmp;
VERIFY(bmp.LoadBitmap(nCheckID));
m_DefaultImgList.Add(&bmp, RGB(255,255,255));
}
// Create a bulletmark bitmap
if(!nBulletID)
{
pbmTempOld=memDC.SelectObject(&bmTemp);
memDC.DrawFrameControl(&rcCheckMark, DFC_MENU, DFCS_MENUBULLET);
memDC.SelectObject(pbmTempOld);
m_DefaultImgList.Add(&bmTemp, RGB(255,255,255));
}
else
{
CBitmap bmp;
VERIFY(bmp.LoadBitmap(nBulletID));
m_DefaultImgList.Add(&bmp, RGB(255,255,255));
}
// Clean up
memDC.DeleteDC();
return TRUE;
}
void COXBitmapMenuOrganizer::Empty(BOOL bCopyText/*=TRUE*/)
{
CString sKey;
CImageList* pImageList;
POSITION pos=m_mapStringToImageList.GetStartPosition();
// Remove all the elements from m_mapStringToImageList and deletes them
while(pos!=NULL)
{
m_mapStringToImageList.GetNextAssoc(pos,sKey,pImageList);
if(pImageList!=&m_DefaultImgList)
{
delete pImageList;
pImageList = NULL;
}
}
m_mapStringToImageList.RemoveAll();
DWORD wKey;
COXImageInfo* pImageInfo;
pos=m_mapCommandToImageInfo.GetStartPosition();
// Remove all the elements from m_mapCommandToImageInfo
while(pos != NULL)
{
m_mapCommandToImageInfo.GetNextAssoc(pos,wKey,pImageInfo);
delete pImageInfo;
pImageInfo = NULL;
}
m_mapCommandToImageInfo.RemoveAll();
// Deletes all the instantiated COXBitmapMenus
while(!m_BitmapMenuList.IsEmpty())
{
COXBitmapMenu* pBitmapMenu=m_BitmapMenuList.RemoveHead();
//TRACE(_T("\nEmpty: Found bitmapmenu %x - Line: %d, %s"), pBitmapMenu, __LINE__, __FILE__);
RestoreBitmapMenu(pBitmapMenu,bCopyText);
//delete pBitmapMenu;
}
}
COXBitmapMenuOrganizer::~COXBitmapMenuOrganizer()
{
Empty(FALSE);
// delete deferred from RestoreBitmapMenu - 9.3 patch
if(m_pDeferedBM != NULL) {
delete m_pDeferedBM;
}
// ... Detach a possible attached frame window
DetachFrameWnd();
for(int nIndex=PtrToInt(m_arrCreatedPopupMenus.GetSize())-1; nIndex>=0; nIndex--)
{
::DestroyMenu(m_arrCreatedPopupMenus[nIndex]);
}
m_arrCreatedPopupMenus.RemoveAll();
ASSERT(g_pfnOldMouseHookProc==NULL);
ASSERT(g_pfnOldKeyboardHookProc==NULL);
}
BOOL COXBitmapMenuOrganizer::AttachFrameWnd(CFrameWnd* pFrameWnd)
{
if((m_pFrameWnd==NULL) && (pFrameWnd != NULL))
{
m_pFrameWnd=pFrameWnd;
VERIFY(SubclassFrameWindow(pFrameWnd));
return TRUE;
}
else
{
TRACE0("COXBitmapMenuOrganizer::AttachFrameWnd : Failed because already attached or frame wnd is NULL\n");
return FALSE;
}
}
CFrameWnd* COXBitmapMenuOrganizer::DetachFrameWnd()
{
CFrameWnd* pFrameWnd=m_pFrameWnd;
if(pFrameWnd != NULL)
{
UnsubclassFrameWindow();
}
m_pFrameWnd=NULL;
Empty();
return pFrameWnd;
}
BOOL COXBitmapMenuOrganizer::SetMenuImage(UINT nCommandID, LPCTSTR pszBitmapID,
int nBitmapIndex, int nCx)
{
if(m_pFrameWnd==NULL)
{
TRACE0("COXBitmapMenuOrganizer::SetMenuImage : Must attach a frame window before calling this function\n");
return FALSE;
}
CString sUResourse=GetUniqueResourceString(pszBitmapID);
CImageList* pImageList;
//Doesn't add if already the resource is asociated with a ImageList
if(!m_mapStringToImageList.Lookup(sUResourse,pImageList))
{
pImageList=new CImageList;
m_mapStringToImageList[sUResourse]=pImageList;
}
else
{
VERIFY(pImageList->DeleteImageList());
}
pImageList->Create(pszBitmapID,nCx,0,RGB(192,192,192));
ASSERT(AfxIsValidAddress(pImageList, sizeof(CImageList)));
COXImageInfo* pImageInfo=NULL;
if(!m_mapCommandToImageInfo.Lookup(nCommandID,pImageInfo))
{
pImageInfo=new COXImageInfo(pImageList,nBitmapIndex);
m_mapCommandToImageInfo[nCommandID]=pImageInfo;
}
else
{
pImageInfo->SetImageList(pImageList);
}
return TRUE;
}
BOOL COXBitmapMenuOrganizer::SetMenuImage(UINT nCommandID, HICON hIcon,
int nCx, int nCy)
{
if(m_pFrameWnd==NULL)
{
TRACE0("COXBitmapMenuOrganizer::SetMenuImage : Must attach a frame window before calling this function\n");
return FALSE;
}
CString sUResourse=GetUniqueResourceString((UINT_PTR)hIcon);
CImageList* pImageList;
//Doesn't add if already the resource is asociated with a ImageList
if(!m_mapStringToImageList.Lookup(sUResourse,pImageList))
{
pImageList=new CImageList;
m_mapStringToImageList[sUResourse]=pImageList;
}
else
{
VERIFY(pImageList->DeleteImageList());
}
VERIFY(pImageList->Create(nCx,nCy,ILC_COLOR24|ILC_MASK,0,0));
VERIFY(pImageList->Add(hIcon)!=-1);
ASSERT(AfxIsValidAddress(pImageList, sizeof(CImageList)));
COXImageInfo* pImageInfo=NULL;
if(!m_mapCommandToImageInfo.Lookup(nCommandID,pImageInfo))
{
pImageInfo=new COXImageInfo(pImageList,0);
m_mapCommandToImageInfo[nCommandID]=pImageInfo;
}
else
{
pImageInfo->SetImageList(pImageList);
}
return TRUE;
}
BOOL COXBitmapMenuOrganizer::SetMenuImage(UINT nCommandID, CBitmap* pbmImage,
COLORREF crMask, int nCx, int nCy)
{
if(m_pFrameWnd==NULL)
{
TRACE0("COXBitmapMenuOrganizer::SetMenuImage : Must attach a frame window before calling this function\n");
return FALSE;
}
CString sUResourse=GetUniqueResourceString((UINT_PTR)pbmImage);
CImageList* pImageList;
//Doesn't add if already the resource is asociated with a ImageList
if(!m_mapStringToImageList.Lookup(sUResourse,pImageList))
{
pImageList=new CImageList;
m_mapStringToImageList[sUResourse]=pImageList;
}
else
{
VERIFY(pImageList->DeleteImageList());
}
VERIFY(pImageList->Create(nCx,nCy,ILC_COLOR24|ILC_MASK,0,0));
VERIFY(pImageList->Add(pbmImage,crMask)!=-1);
ASSERT(AfxIsValidAddress(pImageList, sizeof(CImageList)));
COXImageInfo* pImageInfo=NULL;
if(!m_mapCommandToImageInfo.Lookup(nCommandID,pImageInfo))
{
pImageInfo=new COXImageInfo(pImageList,0);
m_mapCommandToImageInfo[nCommandID]=pImageInfo;
}
else
{
pImageInfo->SetImageList(pImageList);
}
return TRUE;
}
BOOL COXBitmapMenuOrganizer::SetMenuHotImage(UINT nCommandID, LPCTSTR pszBitmapID,
int nBitmapIndex, int nCx)
{
if(m_pFrameWnd==NULL)
{
TRACE(_T("COXBitmapMenuOrganizer::SetMenuHotImage : Must attach a frame window before calling this function\n"));
return FALSE;
}
COXImageInfo* pImageInfo=NULL;
if(!m_mapCommandToImageInfo.Lookup(nCommandID,pImageInfo))
{
TRACE(_T("COXBitmapMenuOrganizer::SetMenuHotImage : normal image must be set for the item before calling this function\n"));
return FALSE;
}
ASSERT(pImageInfo!=NULL);
CImageList* pExistingImageList=pImageInfo->GetImageList();
ASSERT(pExistingImageList!=NULL);
CImageList imageList;
if(!imageList.Create(pszBitmapID,nCx,0,RGB(192,192,192)))
{
TRACE(_T("COXBitmapMenuOrganizer::SetMenuHotImage : failed to load the bitmap\n"));
return FALSE;
}
ASSERT((HIMAGELIST)imageList!=NULL);
HICON hIcon=imageList.ExtractIcon(nBitmapIndex);
ASSERT(hIcon!=NULL);
int nIndex=pExistingImageList->Add(hIcon);
VERIFY(::DestroyIcon(hIcon));
if(nIndex==-1)
{
TRACE(_T("COXBitmapMenuOrganizer::SetMenuHotImage : failed to add bitmap to menu item's image list\n"));
return FALSE;
}
pImageInfo->SetHotIndex(nIndex);
return TRUE;
}
BOOL COXBitmapMenuOrganizer::SetMenuHotImage(UINT nCommandID, HICON hIcon)
{
if(m_pFrameWnd==NULL)
{
TRACE(_T("COXBitmapMenuOrganizer::SetMenuHotImage : Must attach a frame window before calling this function\n"));
return FALSE;
}
COXImageInfo* pImageInfo=NULL;
if(!m_mapCommandToImageInfo.Lookup(nCommandID,pImageInfo))
{
TRACE(_T("COXBitmapMenuOrganizer::SetMenuHotImage : normal image must be set for the item before calling this function\n"));
return FALSE;
}
ASSERT(pImageInfo!=NULL);
CImageList* pExistingImageList=pImageInfo->GetImageList();
ASSERT(pExistingImageList!=NULL);
ASSERT(hIcon!=NULL);
int nIndex=pExistingImageList->Add(hIcon);
if(nIndex==-1)
{
TRACE(_T("COXBitmapMenuOrganizer::SetMenuHotImage : failed to add bitmap to menu item's image list\n"));
return FALSE;
}
pImageInfo->SetHotIndex(nIndex);
return TRUE;
}
BOOL COXBitmapMenuOrganizer::SetMenuHotImage(UINT nCommandID, CBitmap* pbmImage,
COLORREF crMask)
{
if(m_pFrameWnd==NULL)
{
TRACE(_T("COXBitmapMenuOrganizer::SetMenuHotImage : Must attach a frame window before calling this function\n"));
return FALSE;
}
COXImageInfo* pImageInfo=NULL;
if(!m_mapCommandToImageInfo.Lookup(nCommandID,pImageInfo))
{
TRACE(_T("COXBitmapMenuOrganizer::SetMenuHotImage : normal image must be set for the item before calling this function\n"));
return FALSE;
}
ASSERT(pImageInfo!=NULL);
CImageList* pExistingImageList=pImageInfo->GetImageList();
ASSERT(pExistingImageList!=NULL);
ASSERT(pbmImage!=NULL);
int nIndex=pExistingImageList->Add(pbmImage,crMask);
if(nIndex==-1)
{
TRACE(_T("COXBitmapMenuOrganizer::SetMenuHotImage : failed to add bitmap to menu item's image list\n"));
return FALSE;
}
pImageInfo->SetHotIndex(nIndex);
return TRUE;
}
BOOL COXBitmapMenuOrganizer::SetMenuBitmap(UINT nCommandID, LPCTSTR pszBitmapID)
{
if(m_pFrameWnd==NULL)
{
TRACE0("COXBitmapMenuOrganizer::SetMenuBitmap : Must attach a frame window before calling this function\n");
return FALSE;
}
CBitmap Bitmap;
//to get the width of the bitmap
if(!Bitmap.LoadBitmap(pszBitmapID))
return FALSE;
BITMAP BitmapInfo;
Bitmap.GetBitmap(&BitmapInfo);
Bitmap.DeleteObject();
return SetMenuImage(nCommandID, pszBitmapID, 0, BitmapInfo.bmWidth);
}
BOOL COXBitmapMenuOrganizer::SetMenuBitmap(UINT nCommandID, UINT nBitmapID)
{
return SetMenuBitmap(nCommandID,MAKEINTRESOURCE(nBitmapID));
}
BOOL COXBitmapMenuOrganizer::SetMenuHotBitmap(UINT nCommandID, LPCTSTR pszBitmapID)
{
if(m_pFrameWnd==NULL)
{
TRACE0("COXBitmapMenuOrganizer::SetMenuBitmap : Must attach a frame window before calling this function\n");
return FALSE;
}
CBitmap Bitmap;
//to get the width of the bitmap
if(!Bitmap.LoadBitmap(pszBitmapID))
return FALSE;
BITMAP BitmapInfo;
Bitmap.GetBitmap(&BitmapInfo);
Bitmap.DeleteObject();
return SetMenuHotImage(nCommandID, pszBitmapID, 0, BitmapInfo.bmWidth);
}
BOOL COXBitmapMenuOrganizer::SetMenuHotBitmap(UINT nCommandID, UINT nBitmapID)
{
return SetMenuHotBitmap(nCommandID,MAKEINTRESOURCE(nBitmapID));
}
BOOL COXBitmapMenuOrganizer::SetMenuIcon(UINT nCommandID, LPCTSTR pszIconID)
{
if(m_pFrameWnd==NULL)
{
TRACE(_T("COXBitmapMenuOrganizer::SetMenuIcon : Must attach a frame window before calling this function\n"));
return FALSE;
}
HICON hIcon;
//Loads Icon
hIcon=AfxGetApp()->LoadIcon(pszIconID);
if(hIcon==NULL)
return FALSE;
CImageList* pImageList;
CString sUResource=GetUniqueResourceString(pszIconID,FALSE);
//if the Icon resource is not already added
if(!m_mapStringToImageList.Lookup(sUResource,pImageList))
{
pImageList=new CImageList;
//To differentiate between Icon and bitmap add "Icon" at the end
m_mapStringToImageList[sUResource]=pImageList;
}
else
{
VERIFY(pImageList->DeleteImageList());
}
VERIFY(pImageList->Create(GetSystemMetrics(SM_CXICON),
GetSystemMetrics(SM_CYICON),FALSE,1,0));
VERIFY(pImageList->Add(hIcon)!=-1);
ASSERT(AfxIsValidAddress(pImageList, sizeof(CImageList)));
COXImageInfo* pImageInfo=NULL;
if(!m_mapCommandToImageInfo.Lookup(nCommandID,pImageInfo))
{
pImageInfo=new COXImageInfo(pImageList,0);
m_mapCommandToImageInfo[nCommandID]=pImageInfo;
}
else
{
pImageInfo->SetImageList(pImageList);
}
return TRUE;
}
BOOL COXBitmapMenuOrganizer::SetMenuIcon(UINT nCommandID, UINT nIconID)
{
return SetMenuIcon(nCommandID,MAKEINTRESOURCE(nIconID));
}
BOOL COXBitmapMenuOrganizer::SetMenuHotIcon(UINT nCommandID, LPCTSTR pszIconID)
{
if(m_pFrameWnd==NULL)
{
TRACE(_T("COXBitmapMenuOrganizer::SetMenuHotIcon : Must attach a frame window before calling this function\n"));
return FALSE;
}
COXImageInfo* pImageInfo=NULL;
if(!m_mapCommandToImageInfo.Lookup(nCommandID,pImageInfo))
{
TRACE(_T("COXBitmapMenuOrganizer::SetMenuHotIcon : normal image must be set for the item before calling this function\n"));
return FALSE;
}
ASSERT(pImageInfo!=NULL);
CImageList* pExistingImageList=pImageInfo->GetImageList();
ASSERT(pExistingImageList!=NULL);
HICON hIcon;
//Loads Icon
hIcon=AfxGetApp()->LoadIcon(pszIconID);
if(hIcon==NULL)
{
TRACE(_T("COXBitmapMenuOrganizer::SetMenuHotIcon : failed to load the icon\n"));
return FALSE;
}
int nIndex=pExistingImageList->Add(hIcon);
if(nIndex==-1)
{
TRACE(_T("COXBitmapMenuOrganizer::SetMenuHotIcon : failed to add the icon to menu item's image list\n"));
return FALSE;
}
pImageInfo->SetHotIndex(nIndex);
return TRUE;
}
BOOL COXBitmapMenuOrganizer::SetMenuHotIcon(UINT nCommandID, UINT nIconID)
{
return SetMenuHotIcon(nCommandID,MAKEINTRESOURCE(nIconID));
}
COXImageInfo* COXBitmapMenuOrganizer::GetMenuItemImageInfo(UINT nCommandID) const
{
COXImageInfo* pImageInfo=NULL;
m_mapCommandToImageInfo.Lookup(nCommandID,pImageInfo);
return pImageInfo;
}
BOOL COXBitmapMenuOrganizer::AutoSetMenuImage()
{
if(m_pFrameWnd==NULL)
{
TRACE0("COXBitmapMenuOrganizer::AutoSetMenuImage : Must attach a frame window before calling this function\n");
return FALSE;
}
// Empty previous settings
Empty();
CToolBar* pToolBar=NULL;
UINT nID=0;
UINT nStyle=0;
int iImage=0;
int iHotImage=0;
int nListIndex=0;
CString sListIndex;
// Iterate all the control bars and use only the toolbars
POSITION pos=m_pFrameWnd->m_listControlBars.GetHeadPosition();
while (pos != NULL)
{
pToolBar=DYNAMIC_DOWNCAST(CToolBar,
(CControlBar*)m_pFrameWnd->m_listControlBars.GetNext(pos));
//If its a CToolBar
if(pToolBar!=NULL)
{
// Get the original imagelist of the toolbar
HIMAGELIST hOrigImageList=
(HIMAGELIST)pToolBar->SendMessage(TB_GETIMAGELIST);
if(hOrigImageList!=NULL)
{
CImageList origImageList;
CImageList* pOrigImageList=
CImageList::FromHandlePermanent(hOrigImageList);
if(pOrigImageList==NULL)
{
VERIFY(origImageList.Attach(hOrigImageList));
pOrigImageList=&origImageList;
}
ASSERT(pOrigImageList!=NULL);
int nOrigImageCount=pOrigImageList->GetImageCount();
ASSERT(0<nOrigImageCount);
// Get the hot imagelist of the toolbar
HIMAGELIST hHotImageList=
(HIMAGELIST)pToolBar->SendMessage(TB_GETHOTIMAGELIST);
CImageList hotImageList;
CImageList* pHotImageList=NULL;
int nHotImageCount=0;
if(hHotImageList!=NULL)
{
pHotImageList=CImageList::FromHandlePermanent(hHotImageList);
if(pHotImageList==NULL)
{
VERIFY(hotImageList.Attach(hHotImageList));
pHotImageList=&hotImageList;
}
ASSERT(pHotImageList!=NULL);
nHotImageCount=pHotImageList->GetImageCount();
ASSERT(nHotImageCount==nOrigImageCount);
}
CImageList* pNewImageList=new CImageList;
CRect buttonRect;
pToolBar->GetItemRect(0, buttonRect);
int nButtonIndex=0;
#if _MFC_VER > 0x0421
VERIFY(pNewImageList->Create(pOrigImageList));
#else
IMAGEINFO imageInfo;
VERIFY(pOrigImageList->GetImageInfo(0,&imageInfo));
VERIFY(pNewImageList->Create(imageInfo.rcImage.right-imageInfo.rcImage.left,
imageInfo.rcImage.bottom-imageInfo.rcImage.top,
ILC_COLOR24|ILC_MASK,0,0));
for(nButtonIndex=0; nButtonIndex<nOrigImageCount; nButtonIndex++)
{
HICON hIcon=pOrigImageList->ExtractIcon(nButtonIndex);
ASSERT(hIcon!=NULL);
VERIFY(pNewImageList->Add(hIcon)!=-1);
VERIFY(::DestroyIcon(hIcon));
}
#endif
for(nButtonIndex=0; nButtonIndex<nHotImageCount; nButtonIndex++)
{
HICON hIcon=pHotImageList->ExtractIcon(nButtonIndex);
ASSERT(hIcon!=NULL);
VERIFY(pNewImageList->Add(hIcon)!=-1);
VERIFY(::DestroyIcon(hIcon));
}
ASSERT(pNewImageList->GetImageCount()==nHotImageCount+nOrigImageCount);
// Close everything
if((HIMAGELIST)hotImageList!=NULL)
hotImageList.Detach();
if((HIMAGELIST)origImageList!=NULL)
origImageList.Detach();
nListIndex++;
sListIndex.Format(_T("%i"), nListIndex);
m_mapStringToImageList[sListIndex]=pNewImageList;
int nButtonCount=pToolBar->GetToolBarCtrl().GetButtonCount();
// Iterate all buttons on the toolbar
for(nButtonIndex=0; nButtonIndex < nButtonCount; nButtonIndex++)
{
nID=0;
nStyle=0;
iImage=0;
iHotImage=-1;
pToolBar->GetButtonInfo(nButtonIndex, nID, nStyle, iImage);
if(nHotImageCount>0)
{
iHotImage=iImage+nOrigImageCount;
}
//If the Item is not a button
if(nStyle&TBBS_SEPARATOR)
continue;
//Sets the mapping
COXImageInfo* pImageInfo=NULL;
if(!m_mapCommandToImageInfo.Lookup(nID,pImageInfo))
{
pImageInfo=new COXImageInfo(
pNewImageList,iImage,FALSE,iHotImage);
// ... Set new value
m_mapCommandToImageInfo[nID]=pImageInfo;
}
else
{
ASSERT(pImageInfo!=NULL);
pImageInfo->SetImageList(pNewImageList);
pImageInfo->SetIndex(iImage);
pImageInfo->SetHotIndex(iHotImage);
pImageInfo->SetDefaultImgList(FALSE);
}
}
}
}
}
return TRUE;
}
void COXBitmapMenuOrganizer::OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex,
BOOL bSysMenu)
{
ASSERT(pPopupMenu->GetSafeHmenu()!=NULL);
// Replace the attached CMenu by a new COXBitmapMenu object
// if necessary (if not done yet)
CMenu* pMenu=pPopupMenu;
COXBitmapMenu* pBitmapMenu=DYNAMIC_DOWNCAST(COXBitmapMenu, pMenu);
//If a COXBitmapMenu is not already attached to the SubMenu
BOOL bNewBitmapMenu=FALSE;
if(pBitmapMenu==NULL)
{
pBitmapMenu=new COXBitmapMenu();
// Detaches the CMenu
HMENU hMenu=pMenu->Detach();
//Attaches the COXBitmapMenu object to the menu handle
pBitmapMenu->Attach(hMenu);
m_BitmapMenuList.AddTail(pBitmapMenu);
pPopupMenu=pBitmapMenu;
bNewBitmapMenu=TRUE;
}
#if _MFC_VER>0x0421
#ifndef _AFX_NO_OLE_SUPPORT
BOOL bUpdateCmdUI=TRUE;
if(m_pFrameWnd->m_pNotifyHook!=NULL)
{
if(m_pFrameWnd->m_pNotifyHook->m_pActiveItem!=NULL)
{
bUpdateCmdUI=FALSE;
}
}
if(bUpdateCmdUI)
{
#endif // _AFX_NO_OLE_SUPPORT
#endif // _MFC_VER>0x0421
// Before we begin iterating the menuitems to make them ownerdrawn, be sure
// the CmdUI mechanism doesn't want to add or change some menuitems
// (E.g. MRU list)
pBitmapMenu->OnUpdateCmdUI(CWnd::FromHandle(m_hWnd), nIndex, bSysMenu);
#if _MFC_VER>0x0421
#ifndef _AFX_NO_OLE_SUPPORT
}
#endif // _AFX_NO_OLE_SUPPORT
#endif // _MFC_VER>0x0421
ConvertBitmapMenu(pBitmapMenu,bNewBitmapMenu);
pBitmapMenu->
SetCutomizationMode(IsInCustomizationMode(),m_hWndCustomizeOrganizer);
}
LRESULT COXBitmapMenuOrganizer::OnMenuChar(UINT nChar, UINT /* nFlags */,
CMenu* pMenu)
{
//to check wether its a COXBitmapMenu
COXBitmapMenu* pBitmapMenu=DYNAMIC_DOWNCAST(COXBitmapMenu, pMenu);
int nLoWord =0;
int nHiWord =0;
//if its a COXBitmapMenu
if(pBitmapMenu != NULL)
{
int nIndex=0;
//sets the index of the menu item for the corresponding char
if(pBitmapMenu->m_KeyAccessMap.Lookup((TCHAR)nChar,nIndex))
{
nHiWord=2;
nLoWord=nIndex;
}
}
return MAKELRESULT(nLoWord,nHiWord);
}
// Measure item implementation relies on unique control/menu IDs
BOOL COXBitmapMenuOrganizer::OnMeasureItem(int /*nIDCtl*/,
LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
// ... Handle the cases we can handle
BOOL bHandled=TRUE;
CWnd* pWnd=CWnd::FromHandle(m_hWnd);
ASSERT(pWnd != NULL);
if(lpMeasureItemStruct->CtlType==ODT_MENU)
{
ASSERT(lpMeasureItemStruct->CtlID==0);
CMenu* pMenu;
_AFX_THREAD_STATE* pThreadState=AfxGetThreadState();
if(pThreadState->m_hTrackingWindow==m_hWnd)
{
// start from popup
pMenu=CMenu::FromHandle(pThreadState->m_hTrackingMenu);
}
else
{
// start from menubar
pMenu=pWnd->GetMenu();
}
pMenu=OwnFindPopupMenuFromID(pMenu, lpMeasureItemStruct->itemID);
if(pMenu==NULL)
{
if(m_arrPopupMenusTrace.GetSize()>0 && m_nActivePopupMenuCount>0)
{
OXPOPUPMENUTRACE popupMenu=
m_arrPopupMenusTrace[m_nActivePopupMenuCount-1];
pMenu=CMenu::FromHandlePermanent(popupMenu.m_hPopupMenu);
}
}
if(pMenu!=NULL)
{
pMenu->MeasureItem(lpMeasureItemStruct);
}
else
{
TRACE0("COXBitmapMenuOrganizer::OnMeasureItem: Unknown Menu : passing to Default()\n");
bHandled=FALSE;
}
}
else
{
CWnd* pChild=pWnd->GetDescendantWindow(lpMeasureItemStruct->CtlID, TRUE);
if(pChild != NULL && pChild->SendChildNotifyLastMsg())
return bHandled; // eaten by child
}
return bHandled;
}
CString COXBitmapMenuOrganizer::GetUniqueResourceString(UINT_PTR uResourceID,
BOOL bBitmapIcon)
{
CString sRet;
CString sNum;
sNum.Format(_T("%u"), uResourceID);
sNum.ReleaseBuffer();
sRet=CString((TCHAR)CHAR_MAX)+sNum+
CString(bBitmapIcon ? (TCHAR)CHAR_MAX : (TCHAR)CHAR_MIN);
return sRet;
}
CString COXBitmapMenuOrganizer::GetUniqueResourceString(LPCTSTR pszResource,
BOOL bBitmapIcon)
{
if(HIWORD((DWORD_PTR)pszResource)==0)
{
return GetUniqueResourceString(LOWORD((DWORD_PTR)pszResource),bBitmapIcon);
}
else
return CString(pszResource)+
CString(bBitmapIcon ? (TCHAR)CHAR_MAX : (TCHAR)CHAR_MIN);
}
BOOL COXBitmapMenuOrganizer::SubclassFrameWindow(CFrameWnd* pFrameWnd)
// --- In : pFrameWnd : The frame window
// --- Out :
// --- Returns : Whether it was successful or not
// --- Effect : This function subclasses the frame window
{
ASSERT(pFrameWnd != NULL);
ASSERT(pFrameWnd->GetSafeHwnd() != NULL);
ASSERT_VALID(pFrameWnd);
if(m_pfnSuper != NULL)
{
// Already subclasses, check that hWnd and window proc is correct
if((m_hWnd != pFrameWnd->GetSafeHwnd()) ||
((WNDPROC)::GetWindowLongPtr(pFrameWnd->GetSafeHwnd(),GWL_WNDPROC)!=
GlobalMenuOrganizerProc))
{
TRACE0("COXBitmapMenuOrganizer::SubclassFrameWindow : Failed because already subclassed by other window proc\n");
return FALSE;
}
return TRUE;
}
ASSERT(m_hWnd==NULL);
ASSERT(m_pfnSuper==NULL);
#ifdef _DEBUG
COXBitmapMenuOrganizer* pDummyLayoutManager=NULL;
// ... Should not yet be in list of subclassed frame windows
ASSERT(!m_allMenuOrganizers.Lookup(m_hWnd, pDummyLayoutManager));
#endif // _DEBUG
// ... Subclass window (Windows way, not MFC : because may already be subclessed by MFC)
m_hWnd=pFrameWnd->GetSafeHwnd();
m_pfnSuper=(WNDPROC)::GetWindowLongPtr(pFrameWnd->GetSafeHwnd(), GWL_WNDPROC);
::SetWindowLongPtr(m_hWnd, GWL_WNDPROC, (LONG_PTR)GlobalMenuOrganizerProc);
// ... Store in the global map
m_allMenuOrganizers.SetAt(m_hWnd, this);
ASSERT_VALID(this);
return (m_hWnd != NULL);;
}
void COXBitmapMenuOrganizer::UnsubclassFrameWindow()
// --- In :
// --- Out :
// --- Returns :
// --- Effect : This function unsubclasses the window
// It removes this object from the map
// When it is the last in the list it restores the original
// windows procedure
{
ASSERT_VALID(this);
if(m_hWnd != NULL)
{
// Put back original window procedure
ASSERT(m_pfnSuper != NULL);
ASSERT(m_pfnSuper != GlobalMenuOrganizerProc);
// ... GlobalLayoutManagerProc is not used anymore : set WNDPROC back to original value
::SetWindowLongPtr(m_hWnd, GWL_WNDPROC, (LONG_PTR)m_pfnSuper);
// ... Remove use from global map
m_allMenuOrganizers.RemoveKey(m_hWnd);
m_hWnd=NULL;
m_pfnSuper=NULL;
}
ASSERT(m_hWnd==NULL);
ASSERT(m_pfnSuper==NULL);
ASSERT_VALID(this);
}
LRESULT CALLBACK COXBitmapMenuOrganizer::GlobalMenuOrganizerProc(HWND hWnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
// --- In : hWnd :
// uMsg :
// wParam :
// lParam :
// --- Out :
// --- Returns : The result of the message
// --- Effect : This is the global windows procedure of all the menu organizers
// objects that have subclasses a window
{
#if defined (_WINDLL)
#if defined (_AFXDLL)
AFX_MANAGE_STATE(AfxGetAppModuleState());
#else
AFX_MANAGE_STATE(AfxGetStaticModuleState());
#endif
#endif
COXBitmapMenuOrganizer* pBitmapMenuOrganizer=NULL;
VERIFY(m_allMenuOrganizers.Lookup(hWnd, pBitmapMenuOrganizer));
ASSERT_VALID(pBitmapMenuOrganizer);
return pBitmapMenuOrganizer->MenuOrganizerProc(hWnd, uMsg, wParam, lParam);
}
LRESULT COXBitmapMenuOrganizer::MenuOrganizerProc(HWND hWnd, UINT uMsg,
WPARAM wParam, LPARAM lParam)
// --- In : hWnd :
// uMsg :
// wParam :
// lParam :
// --- Out :
// --- Returns: The result of the message
// --- Effect : This is the member function called by the windows procedure of the
// COXBitmapMenuOrganizer object
{
#if defined (_WINDLL)
#if defined (_AFXDLL)
AFX_MANAGE_STATE(AfxGetAppModuleState());
#else
AFX_MANAGE_STATE(AfxGetStaticModuleState());
#endif
#endif
ASSERT_VALID(this);
ASSERT(hWnd==m_hWnd);
// Handling before base class
BOOL bHandled=FALSE;
LRESULT result=0;
// Let the original message procedure handle it first of all
ASSERT(m_pfnSuper != NULL);
ASSERT(m_pfnSuper != GlobalMenuOrganizerProc);
if(uMsg!=WM_MEASUREITEM)
{
result=CallWindowProc(m_pfnSuper,hWnd, uMsg, wParam, lParam);
}
if(!::IsWindow(hWnd))
{
return result;
}
switch (uMsg)
{
case WM_MENUCHAR:
TRACE(_T("COXBitmapMenuOrganizer::MenuOrganizerProc - WM_MENUCHAR\n"));
{
CMenu* pMenu=CMenu::FromHandle((HMENU)lParam);
int nChar=towlower(LOWORD(wParam));
int nFlags=HIWORD(wParam);
result=OnMenuChar(nChar, nFlags, pMenu);
bHandled=TRUE;
break;
}
case WM_INITMENUPOPUP:
TRACE(_T("COXBitmapMenuOrganizer::MenuOrganizerProc - WM_INITMENUPOPUP\n"));
{
CMenu* pPopupMenu=CMenu::FromHandle((HMENU)wParam);
UINT nIndex=(UINT) LOWORD(lParam);
BOOL bSysMenu=(BOOL) HIWORD(lParam);
UpdateActivePopupMenuCount();
int nTraceSize=PtrToInt(m_arrPopupMenusTrace.GetSize());
if(nTraceSize>m_nActivePopupMenuCount)
{
for(int nMenuIndex=nTraceSize-1;
nMenuIndex>=m_nActivePopupMenuCount;
nMenuIndex--)
{
// update map of all popup menu windows
if(nMenuIndex==m_nActivePopupMenuCount)
{
// reuse window object
HWND hPopupMenuWnd=NULL;
if(m_mapPopupMenuWindows.Lookup(
m_arrPopupMenusTrace[nMenuIndex].m_hPopupMenu,
hPopupMenuWnd))
{
m_mapPopupMenuWindows.SetAt((HMENU)wParam,hPopupMenuWnd);
}
}
m_mapPopupMenuWindows.RemoveKey(
m_arrPopupMenusTrace[nMenuIndex].m_hPopupMenu);
m_arrPopupMenusTrace.RemoveAt(nMenuIndex);
}
}
m_nActivePopupMenuCount++;
// Don't make system menu's owner-drawn. We can't retrieve them
// in OnMeasureitem.
if(bSysMenu)
{
TRACE(_T("\nCOXBitmapMenuOrganizer::MenuOrganizerProc: System Menu skipping Ownerdraw\n"));
bHandled=FALSE;
break;
}
OnInitMenuPopup(pPopupMenu, nIndex, bSysMenu);
OXPOPUPMENUTRACE pmt;
pmt.m_hPopupMenu=(HMENU)wParam;
m_arrPopupMenusTrace.Add(pmt);
////////////////////////////////
// the default msg proc further only deals with CmdUI and that is already
// done in OnUpdateCmdUI, so halt further processing
bHandled=TRUE;
break;
}
case WM_MEASUREITEM:
TRACE(_T("COXBitmapMenuOrganizer::MenuOrganizerProc - WM_MEASUREITEM\n"));
{
int nIDCtl=(int)wParam;
LPMEASUREITEMSTRUCT lpMeasureItemStruct=
(LPMEASUREITEMSTRUCT)(LPTSTR)lParam;
result=OnMeasureItem(nIDCtl,lpMeasureItemStruct);
bHandled=TRUE;
break;
}
case WM_COMMAND:
TRACE(_T("COXBitmapMenuOrganizer::MenuOrganizerProc - WM_COMMAND\n"));
{
if(HIWORD(wParam)==0)
{
int nCmdID=LOWORD(wParam);
if(nCmdID==ID_OX_SHOWALLITEMS)
{
// v9.3 update 01 modification Manfred Drasch
POSITION pos=m_BitmapMenuList.GetHeadPosition();
while(pos!=NULL)
{
COXBitmapMenu* pBitmapMenu=m_BitmapMenuList.GetNext(pos);
RestoreBitmapMenu(pBitmapMenu,TRUE);
}
// end modification Manfred Drasch
m_bForceToDisplayHiddenItems=TRUE;
// current menu
UpdateActivePopupMenuCount();
// v9.3 update 01 modification Manfred Drasch
if (m_nActivePopupMenuCount == 0)
break;
// end modification Manfred Drasch
ASSERT(m_nActivePopupMenuCount>0);
OXPOPUPMENUTRACE pmt=
m_arrPopupMenusTrace[m_nActivePopupMenuCount-1];
// handle these event differently for menu bar and standard menu
// in the case the top level popup menu is being displayed.
// In the case GetMenu() returns NULL we assume that we deal
// with menu bar
BOOL bMenuBar=(m_pFrameWnd->GetMenu()==NULL);
BOOL bSpecialCase=(bMenuBar && m_nActivePopupMenuCount==1);
if(bSpecialCase)
{
m_pFrameWnd->LockWindowUpdate();
}
HWND hWndSendRepopulateMsg=NULL;
if(!bSpecialCase)
{
if(m_nActivePopupMenuCount>1)
{
VERIFY(m_mapPopupMenuWindows.Lookup(
m_arrPopupMenusTrace[m_nActivePopupMenuCount-2].
m_hPopupMenu,hWndSendRepopulateMsg));
}
else
{
hWndSendRepopulateMsg=m_pFrameWnd->GetSafeHwnd();
}
ASSERT(hWndSendRepopulateMsg!=NULL);
}
// hide current menu
HWND hWnd=NULL;
VERIFY(m_mapPopupMenuWindows.Lookup(pmt.m_hPopupMenu,hWnd));
ASSERT(hWnd!=NULL);
if(bSpecialCase || bMenuBar)
{
TRACE(_T("MenuOrganizerProc ::SendMessage(hWnd,WM_KEYDOWN,VK_ESCAPE,0x00010001);"));
::SendMessage(hWnd,WM_KEYDOWN,VK_ESCAPE,0x00010001);
}
else
{
TRACE(_T("MenuOrganizerProc ::PostMessage(hWnd,WM_KEYDOWN,VK_ESCAPE,0x00010001);"));
::PostMessage(hWnd,WM_KEYDOWN,VK_ESCAPE,0x00010001);
}
if(bSpecialCase)
{
m_pFrameWnd->UnlockWindowUpdate();
}
// repopulate menus
// v9.3 update 01 modification Manfred Drasch - POSITION pos declared above
// POSITION pos=m_BitmapMenuList.GetHeadPosition();
pos=m_BitmapMenuList.GetHeadPosition();
while(pos!=NULL)
{
COXBitmapMenu* pBitmapMenu=m_BitmapMenuList.GetNext(pos);
ASSERT(pBitmapMenu!=NULL);
HWND hWnd=NULL;
if(!::IsMenu(pBitmapMenu->m_hMenu) ||
!m_mapPopupMenuWindows.Lookup(
pBitmapMenu->GetSafeHmenu(),hWnd) || !::IsWindow(hWnd) ||
pBitmapMenu->GetSafeHmenu()==pmt.m_hPopupMenu)
{
// restore the menu
RestoreBitmapMenu(pBitmapMenu,TRUE);
}
}
if(!bSpecialCase)
{
if(bMenuBar)
{
// display the menu again
::SendMessage(hWndSendRepopulateMsg,
WM_KEYDOWN,VK_RETURN,0x001c0001);
}
else
{
// display the menu again
::PostMessage(hWndSendRepopulateMsg,
WM_KEYDOWN,VK_RETURN,0x001c0001);
}
}
}
else if(nCmdID>0 && IsShowOnlyRecentlyUsedItems() &&
m_arrPopupMenusTrace.GetSize()>0)
{
BOOL bMarkMenuAsChanged=FALSE;
if(!IsRecentlyUsed(nCmdID))
{
AddToRecentlyUsed(nCmdID);
bMarkMenuAsChanged=TRUE;
}
for(int nIndex=1;
nIndex<m_arrPopupMenusTrace.GetSize(); nIndex++)
{
HMENU hPopupMenu=m_arrPopupMenusTrace[nIndex].m_hPopupMenu;
if(!IsSubmenuRecentlyUsed(hPopupMenu))
{
AddSubmenuToRecentlyUsed(hPopupMenu);
bMarkMenuAsChanged=TRUE;
}
}
if(bMarkMenuAsChanged && IsAttached())
{
m_pFrameWnd->SendMessage(WM_OX_MENUCHANGED);
}
}
bHandled=TRUE;
}
break;
}
case WM_ENTERMENULOOP:
TRACE(_T("COXBitmapMenuOrganizer::MenuOrganizerProc - WM_ENTERMENULOOP\n"));
{
if(wParam==0)
{
m_bMainMenuIsActive=TRUE;
}
bHandled=TRUE;
break;
}
case WM_EXITMENULOOP:
TRACE(_T("COXBitmapMenuOrganizer::MenuOrganizerProc - WM_EXITMENULOOP\n"));
{
if(wParam==0)
{
if(m_bForceToDisplayHiddenItems)
{
// repopulate menus
m_bForceToDisplayHiddenItems=FALSE;
if(IsShowOnlyRecentlyUsedItems())
{
POSITION pos=m_BitmapMenuList.GetHeadPosition();
while(pos!=NULL)
{
COXBitmapMenu* pBitmapMenu=m_BitmapMenuList.GetNext(pos);
RestoreBitmapMenu(pBitmapMenu,TRUE);
TRACE(_T("\n %x menu should be removed by RestoreBitmapMenu"), pBitmapMenu);
//delete pBitmapMenu;
}
}
}
m_bMainMenuIsActive=FALSE;
m_nActivePopupMenuCount=0;
}
// unhook mouse messages
if(g_pfnOldMouseHookProc!=NULL)
{
VERIFY(::UnhookWindowsHookEx(g_pfnOldMouseHookProc));
g_pfnOldMouseHookProc=NULL;
}
// unhook keyboard messages
if(g_pfnOldKeyboardHookProc!=NULL)
{
VERIFY(::UnhookWindowsHookEx(g_pfnOldKeyboardHookProc));
g_pfnOldKeyboardHookProc=NULL;
}
bHandled=TRUE;
break;
}
case WM_MENUSELECT:
TRACE(_T("COXBitmapMenuOrganizer::MenuOrganizerProc - WM_MENUSELECT\n"));
{
if(lParam!=NULL && m_arrPopupMenusTrace.GetSize()>0)
{
OXPOPUPMENUTRACE& pmt=
m_arrPopupMenusTrace[m_arrPopupMenusTrace.GetSize()-1];
if(pmt.m_hPopupMenu==(HMENU)lParam)
{
// save Top/Left coordinates of the menu window
CWnd* pPopupWnd=CWnd::GetDesktopWindow()->GetTopWindow();
ASSERT(pPopupWnd!=NULL);
CRect rectPopupWnd;
pPopupWnd->GetWindowRect(rectPopupWnd);
pmt.m_ptTopLeft=rectPopupWnd.TopLeft();
////////////////////////////////
m_mapPopupMenuWindows.
SetAt((HMENU)lParam,pPopupWnd->GetSafeHwnd());
if(IsShowOnlyRecentlyUsedItems())
{
// setup hooks for mouse and keyboard messages
if(g_pfnOldMouseHookProc==NULL)
{
g_pfnOldMouseHookProc=::SetWindowsHookEx(WH_MOUSE,
MenuMouseHookProc,NULL,::GetCurrentThreadId());
}
if(g_pfnOldKeyboardHookProc==NULL)
{
g_pfnOldKeyboardHookProc=::SetWindowsHookEx(WH_KEYBOARD,
MenuKeyboardHookProc,NULL,::GetCurrentThreadId());
}
//////////////////////////////////////////////
}
}
}
/*
UINT nFlags=HIWORD(wParam);
if((nFlags&MF_HILITE)!=0 && !(nFlags==0xffff && lParam==NULL) &&
LOWORD(wParam)!=-1)
{
while(m_nActivePopupMenuCount>0 && m_arrPopupMenusTrace[
m_nActivePopupMenuCount-1].m_hPopupMenu!=(HMENU)lParam)
{
m_nActivePopupMenuCount--;
}
}
*/
break;
}
case WM_OX_SAVEMENUSTATE:
TRACE(_T("COXBitmapMenuOrganizer::MenuOrganizerProc - WM_OX_SAVEMENUSTATE\n"));
{
// save info about recently used submenu items
HMENU hMenu=(HMENU)wParam;
CString sKey=(LPCTSTR)lParam;
if(hMenu!=NULL)
{
VERIFY(SaveRUSubmenusState(hMenu,
sKey+_T("_RecentlyUsedSubmenuItems")));
}
}
case WM_OX_LOADMENUSTATE:
TRACE(_T("COXBitmapMenuOrganizer::MenuOrganizerProc\n"));
{
// load info about recently used submenu items
HMENU hMenu=(HMENU)wParam;
CString sKey=(LPCTSTR)lParam;
if(hMenu!=NULL)
{
VERIFY(LoadRUSubmenusState(hMenu,
sKey+_T("_RecentlyUsedSubmenuItems")));
}
}
default:
// Do nothing special
;
}
return result;
}
void COXBitmapMenuOrganizer::UpdateActivePopupMenuCount()
{
int nTraceLength=PtrToInt(m_arrPopupMenusTrace.GetSize());
if(nTraceLength==0)
{
m_nActivePopupMenuCount=0;
return;
}
int nIndex=0;
for(nIndex=0; nIndex<nTraceLength; nIndex++)
{
HWND hWnd=NULL;
if(!m_mapPopupMenuWindows.
Lookup(m_arrPopupMenusTrace[nIndex].m_hPopupMenu,hWnd))
{
break;
}
if(!::IsWindow(hWnd) || !::IsWindowVisible(hWnd))
{
break;
}
}
if(nIndex<m_nActivePopupMenuCount)
{
m_nActivePopupMenuCount=nIndex;
}
}
CMenu* COXBitmapMenuOrganizer::OwnFindPopupMenuFromID(CMenu* pMenu, UINT nID)
{
ASSERT_VALID(pMenu);
// walk through all items, looking for ID match
UINT_PTR nItems=pMenu->GetMenuItemCount();
UINT_PTR nItemID=0;
for (int iItem=0; iItem < (int)nItems; iItem++)
{
// Always check the menu item itself first
nItemID=pMenu->GetMenuItemID(iItem);
if(nItemID==(UINT)-1)
{
// ... If it is a cascade menu, use its handle instead of its ID (which is always -1)
// So appearently Windows passes the HMENU instead of the ID for cascade manus
// in MEASUREITEMSTRUCT when sending WM_MEASUREITEM
nItemID=(UINT_PTR)pMenu->GetSubMenu(iItem)->GetSafeHmenu();
}
if(nItemID==nID || nID==-1)
{
// ... it is an item inside our popup
pMenu=CMenu::FromHandlePermanent(pMenu->m_hMenu);
return pMenu;
}
// Then check child menus
CMenu* pPopup=pMenu->GetSubMenu(iItem);
if(pPopup != NULL)
{
// ... Recurse to child popup
pPopup=OwnFindPopupMenuFromID(pPopup, nID);
// ... Check popups on this popup
if(pPopup != NULL)
return pPopup;
}
}
// ... Not found
return NULL;
}
void COXBitmapMenuOrganizer::ConvertBitmapMenu(COXBitmapMenu* pBitmapMenu,
BOOL bNewBitmapMenu/*=TRUE*/)
{
ASSERT(pBitmapMenu!=NULL);
UINT uItemID;
COXImageInfo* pImageInfo;
int nCount=pBitmapMenu->GetMenuItemCount();
int nAmpIndex;
MENUITEMINFO miiGet, miiPut;
CString sText;
COXArrSavedMenuItem arrSavedMenuItems;
BOOL bPrevSepBeforeHidden=TRUE;
//Make all the menu items OwnerDrawn
int nIndex=0;
for(nIndex=0; nIndex < nCount; nIndex++)
{
// Even cascade menu item should be made owner drawn
// so that the text of these items is aligned properly
::ZeroMemory(&miiGet, sizeof(miiGet));
miiGet.cbSize=sizeof(miiGet);
miiGet.fMask=MIIM_TYPE|MIIM_ID|MIIM_STATE|MIIM_DATA|
MIIM_SUBMENU|MIIM_CHECKMARKS;
miiGet.fType=MFT_STRING;
miiGet.dwTypeData = NULL;
::GetMenuItemInfo(pBitmapMenu->GetSafeHmenu(),nIndex,TRUE,&miiGet);
++miiGet.cch;
miiGet.dwTypeData=sText.GetBuffer(miiGet.cch + 1);
// Gets the item info
miiGet.dwTypeData[0]=_T('\0');
::GetMenuItemInfo(pBitmapMenu->GetSafeHmenu(),nIndex,TRUE,&miiGet);
sText.ReleaseBuffer();
#if _MFC_VER>0x0421
#ifndef _AFX_NO_OLE_SUPPORT
if(miiGet.fType & MFT_SEPARATOR)
{
if(m_pFrameWnd->m_pNotifyHook!=NULL)
{
if(m_pFrameWnd->m_pNotifyHook->m_pActiveItem!=NULL)
{
// continue;
}
}
}
#endif // _AFX_NO_OLE_SUPPORT
#endif // _MFC_VER>0x0421
if(bNewBitmapMenu && !m_bForceToDisplayHiddenItems &&
!IsInCustomizationMode() && IsShowOnlyRecentlyUsedItems() &&
(!IsRecentlyUsed(miiGet.wID) ||
!IsSubmenuRecentlyUsed(miiGet.hSubMenu) ||
((miiGet.fType & MFT_SEPARATOR) && bPrevSepBeforeHidden)))
{
OXSAVEDMENUITEM smi;
smi.nIndex=nIndex;
smi.miInfo=miiGet;
if(miiGet.hSubMenu!=NULL)
{
smi.miInfo.hSubMenu=CopyPopupMenu(miiGet.hSubMenu);
}
smi.sText=sText;
ASSERT(smi.miInfo.wID!=-1 || ::IsMenu(smi.miInfo.hSubMenu));
arrSavedMenuItems.Add(smi);
if(!(miiGet.fType & MFT_SEPARATOR) && !bPrevSepBeforeHidden && nIndex>0)
{
if(pBitmapMenu->GetMenuItemID(nIndex-1)==0)
{
bPrevSepBeforeHidden=TRUE;
}
}
}
else
{
BOOL bConvertToOwnerdraw=((miiGet.fType & MFT_OWNERDRAW)==0);
uItemID=((miiGet.hSubMenu==NULL) ? miiGet.wID : (UINT)-1);
//Makes the item owner-drawn and sets the ItemInfo to the ItemData
// which in turn will be used in COXBitmapMenu while drawing
::ZeroMemory(&miiPut, sizeof(miiPut));
miiPut.cbSize=sizeof(miiPut);
miiPut.fMask=(bConvertToOwnerdraw ? MIIM_TYPE : 0) | MIIM_DATA | MIIM_ID;
miiPut.fType=(miiGet.fType & ~MFT_STRING) | MFT_OWNERDRAW;
switch(miiGet.wID)
{
// Restore
case 61728:
miiPut.wID = ID_OXBITMAPMENU_RESTORE;
break;
// Minimize
case 61472:
miiPut.wID = ID_OXBITMAPMENU_MINIMIZE;
break;
// Close
case 61536:
miiPut.wID = ID_OXBITMAPMENU_CLOSE;
break;
default:
miiPut.wID = miiGet.wID;
}
// Gets the ImageInfo for the command if exist
if(!m_mapCommandToImageInfo.Lookup(uItemID,pImageInfo))
{
CImageList* pImageList;
CString sUResource=GetUniqueResourceString(uItemID,FALSE);
// if the Normal menuitem is not already added
if(!m_mapStringToImageList.Lookup(sUResource, pImageList))
{
m_mapStringToImageList[sUResource]=pImageList=&m_DefaultImgList;
}
ASSERT(AfxIsValidAddress(pImageList, sizeof(CImageList)));
pImageInfo=new COXImageInfo(pImageList, 0, TRUE);
//sets the mapping between MenuItem ID and Image Info
m_mapCommandToImageInfo[uItemID]=pImageInfo;
}
COXItemInfo* pItemInfo=NULL;
if(miiGet.dwItemData != 0 && !bNewBitmapMenu)
{
pItemInfo=(COXItemInfo*)miiGet.dwItemData;
miiPut.dwItemData=(DWORD_PTR)pItemInfo;
if(miiGet.fType==MFT_STRING)
{
pItemInfo->SetText(sText);
}
}
else
{
pItemInfo=new COXItemInfo(pImageInfo, sText);
TRACE(_T("\nCreated COXItemInfo at %x - Line: %d, %s"), pItemInfo, __LINE__, __FILE__);
miiPut.dwItemData=(DWORD_PTR)pItemInfo;
pBitmapMenu->AddItemInfo(pItemInfo);
}
// Put the menuitem with the new data back in its place
::SetMenuItemInfo(pBitmapMenu->GetSafeHmenu(),nIndex,TRUE,&miiPut);
// A mapping is maintained for keyboard access chars of menu items and
// the commands IDs.
nAmpIndex=sText.Find('&');
TCHAR LoCase=_T('\0');
if(nAmpIndex!=-1)
{
LoCase=(TCHAR)towlower(sText[nAmpIndex+1]);
(pBitmapMenu->m_KeyAccessMap)[LoCase]=nIndex;
}
bPrevSepBeforeHidden=FALSE;
}
}
if(bNewBitmapMenu)
{
if(arrSavedMenuItems.GetSize()>0)
{
// Gets the ImageInfo for the command if exist
if(!m_mapCommandToImageInfo.Lookup(ID_OX_SHOWALLITEMS,pImageInfo))
{
CString sUResource=GetUniqueResourceString(ID_OX_SHOWALLITEMS,FALSE);
CImageList* pImageList;
m_mapStringToImageList[sUResource]=pImageList=&m_DefaultImgList;
ASSERT(AfxIsValidAddress(pImageList, sizeof(CImageList)));
pImageInfo=new COXImageInfo(pImageList, 0, TRUE);
//sets the mapping between MenuItem ID and Image Info
m_mapCommandToImageInfo[ID_OX_SHOWALLITEMS]=pImageInfo;
}
COXItemInfo* pItemInfo=new COXItemInfo(pImageInfo,_T(""));
pBitmapMenu->AddItemInfo(pItemInfo);
// add expansion item
pBitmapMenu->
AppendMenu(MF_OWNERDRAW,ID_OX_SHOWALLITEMS,(LPCTSTR)pItemInfo);
}
ASSERT(!m_mapSavedMenuItems.RemoveKey(pBitmapMenu));
m_mapSavedMenuItems.SetAt(pBitmapMenu,arrSavedMenuItems);
for(nIndex= PtrToInt(arrSavedMenuItems.GetSize())-1; nIndex>=0; nIndex--)
{
OXSAVEDMENUITEM smi=arrSavedMenuItems[nIndex];
VERIFY(pBitmapMenu->DeleteMenu(smi.nIndex,MF_BYPOSITION));
}
}
//Calculates the various internal extents
pBitmapMenu->CalcExtents();
}
void COXBitmapMenuOrganizer::RestoreBitmapMenu(COXBitmapMenu* pBitmapMenu,
BOOL bCopyText/*=TRUE*/)
{
BOOL bDeferDeletion = FALSE;
// remove it from the list if it hasn't been removed yet
POSITION pos=m_BitmapMenuList.GetHeadPosition();
while(pos!=NULL)
{
if(m_BitmapMenuList.GetAt(pos)==pBitmapMenu)
{
TRACE(_T("\nRemoving bitmapmenu at %x - Line: %d, %s"), pBitmapMenu, __LINE__, __FILE__);
m_BitmapMenuList.RemoveAt(pos);
break;
}
m_BitmapMenuList.GetNext(pos);
}
// remove expansion item
if(::IsMenu(pBitmapMenu->m_hMenu) && pBitmapMenu->GetMenuItemCount()>0)
{
if(pBitmapMenu->GetMenuItemID(pBitmapMenu->GetMenuItemCount()-1)==
ID_OX_SHOWALLITEMS)
{
bDeferDeletion = TRUE;
pBitmapMenu->DeleteMenu(pBitmapMenu->GetMenuItemCount()-1,MF_BYPOSITION);
}
}
MENUITEMINFO miiGet, miiPut;
CString sText;
if(bCopyText && ::IsMenu(pBitmapMenu->m_hMenu))
{
int nCount=pBitmapMenu->GetMenuItemCount();
// Put the strings of the menu's back in, the ownerdraw state has emptied them.
for(int nIndex=0; nIndex < nCount; nIndex++)
{
::ZeroMemory(&miiGet, sizeof(miiGet));
miiGet.cbSize=sizeof(miiGet);
miiGet.fMask=MIIM_TYPE | MIIM_DATA;
// Gets the item info
::GetMenuItemInfo(pBitmapMenu->GetSafeHmenu(), nIndex, TRUE, &miiGet);
// all item must have been converted to ownerdraw
// only the items that has been added programmatically
// and hasn't been displayed yet won't have ownerdraw style
if((miiGet.fType&MFT_OWNERDRAW)!=0)
{
COXItemInfo* pItemInfo=(COXItemInfo*)miiGet.dwItemData;
if(pItemInfo!=NULL)
{
sText=pItemInfo->GetText();
// Put the text text back into the menu
::ZeroMemory(&miiPut, sizeof(miiPut));
miiPut.cbSize=sizeof(miiPut);
miiPut.fMask=MIIM_TYPE|MIIM_DATA;
if((miiGet.fType&MFT_SEPARATOR)==0)
{
miiPut.fType=(miiGet.fType&~MFT_OWNERDRAW)|MFT_STRING;
}
else
{
miiPut.fType=(miiGet.fType&~MFT_OWNERDRAW);
}
miiPut.cch=sText.GetLength();
miiPut.dwTypeData=sText.GetBuffer(miiPut.cch);
miiPut.dwItemData=0;
// Put the menuitem with the new data back in its place
::SetMenuItemInfo(pBitmapMenu->GetSafeHmenu(),nIndex,TRUE,&miiPut);
sText.ReleaseBuffer();
}
}
}
}
COXArrSavedMenuItem arrSavedMenuItems;
VERIFY(m_mapSavedMenuItems.Lookup(pBitmapMenu,arrSavedMenuItems));
if(::IsMenu(pBitmapMenu->m_hMenu))
{
for(int nIndex=0; nIndex<arrSavedMenuItems.GetSize(); nIndex++)
{
OXSAVEDMENUITEM smi=arrSavedMenuItems[nIndex];
smi.miInfo.dwTypeData=(LPTSTR)((LPCTSTR)smi.sText);
VERIFY(::InsertMenuItem(pBitmapMenu->GetSafeHmenu(),
smi.nIndex,TRUE,&smi.miInfo));
}
}
VERIFY(m_mapSavedMenuItems.RemoveKey(pBitmapMenu));
//TRACE(_T("\npBitmapMenu at %0x\n"),pBitmapMenu);
// - 9.3 patch - defer deletion of bitmap till restored bitmap displayed
if(!bDeferDeletion) {
pBitmapMenu->Detach();
delete pBitmapMenu;
pBitmapMenu = NULL;
}
else {
if( m_pDeferedBM != NULL) {
delete m_pDeferedBM;
}
pBitmapMenu->Detach();
m_pDeferedBM = pBitmapMenu;
}
}
void COXBitmapMenuOrganizer::ShowOnlyRecentlyUsedItems(BOOL bShowOnlyRecentlyUsed)
{
if(bShowOnlyRecentlyUsed!=m_bShowOnlyRecentlyUsed)
{
m_bShowOnlyRecentlyUsed=bShowOnlyRecentlyUsed;
POSITION pos=m_BitmapMenuList.GetHeadPosition();
while(pos!=NULL)
{
COXBitmapMenu* pBitmapMenu=m_BitmapMenuList.GetNext(pos);
COXBitmapMenuPopupWnd* pPopupWnd=pBitmapMenu->GetPopupWnd();
if(pPopupWnd!=NULL && ::IsWindow(pPopupWnd->GetSafeHwnd()))
{
pPopupWnd->OnMenuChanged();
}
}
}
}
BOOL COXBitmapMenuOrganizer::ExcludeFromRecentlyUsed(int nCmdID)
{
ASSERT(nCmdID>=0);
if(nCmdID==0)
{
// separators cannot be hidden
return FALSE;
}
if(!IsRecentlyUsed(nCmdID))
{
// not a recently used item
return FALSE;
}
m_mapHiddenCommands.SetAt(nCmdID,0);
return TRUE;
}
BOOL COXBitmapMenuOrganizer::ExcludeFromRecentlyUsed(CMenu* pMenu, int nItemIndex)
{
ASSERT(pMenu!=NULL);
ASSERT(nItemIndex>=0 && nItemIndex<(int)pMenu->GetMenuItemCount());
int nCmdID=(int)pMenu->GetMenuItemID(nItemIndex);
if(nCmdID==-1)
{
// submenu
ASSERT(pMenu->GetSubMenu(nItemIndex)!=NULL);
return ExcludeSubmenuFromRecentlyUsed(
pMenu->GetSubMenu(nItemIndex)->GetSafeHmenu());
}
else
{
return ExcludeFromRecentlyUsed(nCmdID);
}
}
BOOL COXBitmapMenuOrganizer::ExcludeSubmenuFromRecentlyUsed(HMENU hPopupMenu)
{
ASSERT(hPopupMenu!=NULL);
if(!IsSubmenuRecentlyUsed(hPopupMenu))
{
// not a recently used submenu
return FALSE;
}
m_mapHiddenSubmenus.SetAt(hPopupMenu,0);
return TRUE;
}
BOOL COXBitmapMenuOrganizer::AddToRecentlyUsed(int nCmdID)
{
ASSERT(nCmdID>0);
if(!m_mapHiddenCommands.RemoveKey(nCmdID))
{
// this command is already marked as recently used
return FALSE;
}
return TRUE;
}
BOOL COXBitmapMenuOrganizer::AddToRecentlyUsed(CMenu* pMenu, int nItemIndex)
{
ASSERT(pMenu!=NULL);
ASSERT(nItemIndex>=0 && nItemIndex<(int)pMenu->GetMenuItemCount());
int nCmdID=(int)pMenu->GetMenuItemID(nItemIndex);
if(nCmdID==-1)
{
// submenu
ASSERT(pMenu->GetSubMenu(nItemIndex)!=NULL);
return AddSubmenuToRecentlyUsed(pMenu->GetSubMenu(nItemIndex)->GetSafeHmenu());
}
else
{
return AddToRecentlyUsed(nCmdID);
}
}
BOOL COXBitmapMenuOrganizer::AddSubmenuToRecentlyUsed(HMENU hPopupMenu)
{
ASSERT(hPopupMenu!=NULL);
if(!m_mapHiddenSubmenus.RemoveKey(hPopupMenu))
{
// this submenu is already marked as recently used
return FALSE;
}
return TRUE;
}
BOOL COXBitmapMenuOrganizer::IsRecentlyUsed(int nCmdID) const
{
int nDummy=-1;
return (!m_mapHiddenCommands.Lookup(nCmdID,nDummy));
}
BOOL COXBitmapMenuOrganizer::IsRecentlyUsed(CMenu* pMenu, int nItemIndex) const
{
if (nItemIndex == -1)
return TRUE;
ASSERT(pMenu!=NULL);
ASSERT(nItemIndex>=0 && nItemIndex<(int)pMenu->GetMenuItemCount());
int nCmdID=(int)pMenu->GetMenuItemID(nItemIndex);
if(nCmdID==-1)
{
// submenu
ASSERT(pMenu->GetSubMenu(nItemIndex)!=NULL);
return IsSubmenuRecentlyUsed(pMenu->GetSubMenu(nItemIndex)->GetSafeHmenu());
}
else
{
return IsRecentlyUsed(nCmdID);
}
}
BOOL COXBitmapMenuOrganizer::IsSubmenuRecentlyUsed(HMENU hPopupMenu) const
{
int nDummy=-1;
return (!m_mapHiddenSubmenus.Lookup(hPopupMenu,nDummy));
}
void COXBitmapMenuOrganizer::SetCutomizationMode(BOOL bInCutomizationMode,
HWND hWndCustomizeOrganizer/*=NULL*/)
{
if(m_bInCutomizationMode!=bInCutomizationMode)
{
m_bInCutomizationMode=bInCutomizationMode;
if(m_bInCutomizationMode)
{
if(IsShowOnlyRecentlyUsedItems() && !m_bForceToDisplayHiddenItems)
{
POSITION pos=m_BitmapMenuList.GetHeadPosition();
while(pos!=NULL)
{
COXBitmapMenu* pBitmapMenu=m_BitmapMenuList.GetNext(pos);
RestoreBitmapMenu(pBitmapMenu,TRUE);
// delete pBitmapMenu;
}
}
}
}
m_hWndCustomizeOrganizer=hWndCustomizeOrganizer;
}
BOOL COXBitmapMenuOrganizer::SaveRUCommandsState(LPCTSTR lpszSubKey)
{
#ifndef _MAC
CWinApp* pApp=AfxGetApp();
CString sProfileName=lpszSubKey;
if(sProfileName.IsEmpty())
{
sProfileName=_T("RecentlyUsedMenuItems");
}
CString sValueName=_T("RUContents");
CMemFile memFile;
CArchive ar(&memFile,CArchive::store);
VERIFY(SaveRUCommandsContents(ar));
ar.Close();
int nBufferLength=(int)memFile.GetLength();
ASSERT(nBufferLength>0);
BYTE* pBuffer=memFile.Detach();
pApp->WriteProfileBinary(sProfileName,sValueName,pBuffer,nBufferLength);
::free((void*)pBuffer);
sValueName=_T("RUItemsDataSize");
pApp->WriteProfileInt(sProfileName,sValueName,nBufferLength);
return TRUE;
#else
return FALSE;
#endif
}
BOOL COXBitmapMenuOrganizer::LoadRUCommandsState(LPCTSTR lpszSubKey)
{
#ifndef _MAC
CWinApp* pApp=AfxGetApp();
CString sProfileName=lpszSubKey;
if(sProfileName.IsEmpty())
{
sProfileName=_T("RecentlyUsedMenuItems");
}
CString sValueName=_T("RUItemsDataSize");
int nSavedBufferLength=
pApp->GetProfileInt(sProfileName,sValueName,-1);
sValueName=_T("RUContents");
if(nSavedBufferLength!=-1)
{
ASSERT(nSavedBufferLength>0);
UINT nBufferLength=0;
BYTE* pBuffer=NULL;
if(pApp->GetProfileBinary(sProfileName,sValueName,&pBuffer,&nBufferLength))
{
ASSERT(nBufferLength>0);
ASSERT(pBuffer!=NULL);
CMemFile memFile(pBuffer,nBufferLength);
CArchive ar(&memFile,CArchive::load);
VERIFY(LoadRUCommandsContents(ar));
ar.Close();
memFile.Detach();
delete[] pBuffer;
}
}
return TRUE;
#else
return FALSE;
#endif
}
BOOL COXBitmapMenuOrganizer::SaveRUCommandsContents(CArchive& ar)
{
int nCommandsCount=PtrToInt(m_mapHiddenCommands.GetCount());
ar<<nCommandsCount;
POSITION pos=m_mapHiddenCommands.GetStartPosition();
while(pos!=NULL)
{
int nCmdID=-1;
int nIndex=-1;
m_mapHiddenCommands.GetNextAssoc(pos,nCmdID,nIndex);
ASSERT(nCmdID>0);
ar<<nCmdID;
}
return TRUE;
}
BOOL COXBitmapMenuOrganizer::LoadRUCommandsContents(CArchive& ar)
{
// remove all items from the list of hidden commands
m_mapHiddenCommands.RemoveAll();
DWORD dwCommandsCount=0;
ar>>dwCommandsCount;
for(int nIndex=0; nIndex<(int)dwCommandsCount; nIndex++)
{
DWORD dwCmdID=0;
ar>>dwCmdID;
ASSERT(dwCmdID>0);
ExcludeFromRecentlyUsed((int)dwCmdID);
}
return TRUE;
}
BOOL COXBitmapMenuOrganizer::SaveRUSubmenusState(HMENU hMenu, LPCTSTR lpszSubKey)
{
#ifndef _MAC
ASSERT(hMenu!=NULL);
ASSERT(::IsMenu(hMenu));
CWinApp* pApp=AfxGetApp();
CString sProfileName=lpszSubKey;
if(sProfileName.IsEmpty())
{
sProfileName=_T("RecentlyUsedSubmenuItems");
}
CString sValueName=_T("RUContents");
CMemFile memFile;
CArchive ar(&memFile,CArchive::store);
VERIFY(SaveRUSubmenusContents(hMenu,ar));
ar.Close();
int nBufferLength=(int)memFile.GetLength();
ASSERT(nBufferLength>0);
BYTE* pBuffer=memFile.Detach();
pApp->WriteProfileBinary(sProfileName,sValueName,pBuffer,nBufferLength);
::free((void*)pBuffer);
sValueName=_T("RUItemsDataSize");
pApp->WriteProfileInt(sProfileName,sValueName,nBufferLength);
return TRUE;
#else
return FALSE;
#endif
}
BOOL COXBitmapMenuOrganizer::LoadRUSubmenusState(HMENU hMenu, LPCTSTR lpszSubKey)
{
#ifndef _MAC
ASSERT(hMenu!=NULL);
ASSERT(::IsMenu(hMenu));
CWinApp* pApp=AfxGetApp();
CString sProfileName=lpszSubKey;
if(sProfileName.IsEmpty())
{
sProfileName=_T("RecentlyUsedSubmenuItems");
}
CString sValueName=_T("RUItemsDataSize");
int nSavedBufferLength=
pApp->GetProfileInt(sProfileName,sValueName,-1);
sValueName=_T("RUContents");
if(nSavedBufferLength!=-1)
{
ASSERT(nSavedBufferLength>0);
UINT nBufferLength=0;
BYTE* pBuffer=NULL;
if(pApp->GetProfileBinary(sProfileName,sValueName,&pBuffer,&nBufferLength))
{
ASSERT(nBufferLength>0);
ASSERT(pBuffer!=NULL);
CMemFile memFile(pBuffer,nBufferLength);
CArchive ar(&memFile,CArchive::load);
VERIFY(LoadRUSubmenusContents(hMenu,ar));
ar.Close();
memFile.Detach();
delete[] pBuffer;
}
}
return TRUE;
#else
return FALSE;
#endif
}
BOOL COXBitmapMenuOrganizer::SaveRUSubmenusContents(HMENU hMenu, CArchive& ar)
{
ASSERT(hMenu!=NULL);
ASSERT(::IsMenu(hMenu));
int nSubmenusCount=PtrToInt(m_mapHiddenSubmenus.GetCount());
ar<<nSubmenusCount;
POSITION pos=m_mapHiddenSubmenus.GetStartPosition();
while(pos!=NULL)
{
HMENU hPopupMenu=NULL;
int nIndex=-1;
m_mapHiddenSubmenus.GetNextAssoc(pos,hPopupMenu,nIndex);
ASSERT(hPopupMenu!=NULL);
if(::IsMenu(hPopupMenu))
{
CArray<int,int> arrPath;
if(FindPopupMenuPath(hPopupMenu,hMenu,arrPath))
{
for(int nIndex=0; nIndex<arrPath.GetSize(); nIndex++)
{
ar<<arrPath[nIndex];
}
}
}
// end of path
ar<<-1;
}
return TRUE;
}
BOOL COXBitmapMenuOrganizer::LoadRUSubmenusContents(HMENU hMenu, CArchive& ar)
{
ASSERT(hMenu!=NULL);
ASSERT(::IsMenu(hMenu));
// remove all items from the list of hidden submenus
m_mapHiddenSubmenus.RemoveAll();
DWORD dwSubmenusCount=0;
ar>>dwSubmenusCount;
for(int nIndex=0; nIndex<(int)dwSubmenusCount; nIndex++)
{
DWORD dwItemIndex;
CArray<int,int> arrPath;
do
{
ar>>dwItemIndex;
if(dwItemIndex!=-1)
{
arrPath.Add(dwItemIndex);
}
} while(dwItemIndex!=-1);
HMENU hPopupMenu=NULL;
if(arrPath.GetSize()>0)
{
HMENU hParentMenu=hMenu;
for(int nPathIndex=0; nPathIndex<arrPath.GetSize(); nPathIndex++)
{
hParentMenu=GetSubMenu(hParentMenu,arrPath[nPathIndex]);
if(hParentMenu==NULL)
{
TRACE(_T("COXBitmapMenuOrganizer::LoadRUSubmenusContents: failed to load RU submenu\n"));
break;
}
}
hPopupMenu=hParentMenu;
}
if(hPopupMenu!=NULL)
{
ExcludeSubmenuFromRecentlyUsed(hPopupMenu);
}
}
return TRUE;
}
COXBitmapMenuOrganizer* COXBitmapMenuOrganizer::FindOrganizer(HWND hWnd)
{
COXBitmapMenuOrganizer* pOrganizer=NULL;
if(!m_allMenuOrganizers.Lookup(hWnd,pOrganizer))
{
return NULL;
}
else
{
return pOrganizer;
}
}
BOOL COXBitmapMenuOrganizer::IsTopLevelPopupMenu(HMENU hPopupMenu)
{
ASSERT(hPopupMenu!=NULL);
ASSERT(::IsMenu(hPopupMenu));
ASSERT(IsAttached());
CMenu* pMenu=m_pFrameWnd->GetMenu();
if(pMenu==NULL)
return FALSE;
BOOL bFound=FALSE;
for(int nIndex=0; nIndex<(int)pMenu->GetMenuItemCount(); nIndex++)
{
CMenu* pTopLevelPopupMenu=pMenu->GetSubMenu(nIndex);
if(pTopLevelPopupMenu!=NULL &&
pTopLevelPopupMenu->GetSafeHmenu()==hPopupMenu)
{
bFound=TRUE;
break;
}
}
return bFound;
}
HMENU COXBitmapMenuOrganizer::CopyPopupMenu(HMENU hMenuDest)
{
HMENU hMenu=::CreatePopupMenu();
ASSERT(hMenu!=NULL);
m_arrCreatedPopupMenus.Add(hMenu);
if(!IsSubmenuRecentlyUsed(hMenuDest))
{
AddSubmenuToRecentlyUsed(hMenuDest);
ExcludeSubmenuFromRecentlyUsed(hMenu);
}
MENUITEMINFO miInfo;
CString sText;
for(int nIndex=0; nIndex<::GetMenuItemCount(hMenuDest); nIndex++)
{
// Even cascade menu item should be made owner drawn
// so that the text of these items is align properly
::ZeroMemory(&miInfo,sizeof(miInfo));
miInfo.cbSize=sizeof(miInfo);
miInfo.fMask=MIIM_TYPE|MIIM_ID|MIIM_STATE|MIIM_DATA|
MIIM_SUBMENU|MIIM_CHECKMARKS;
miInfo.fType=MFT_STRING;
miInfo.cch=300;
miInfo.dwTypeData=sText.GetBuffer(miInfo.cch);
// Gets the item info
miInfo.dwTypeData[0]=_T('\0');
::GetMenuItemInfo(hMenuDest,nIndex,TRUE,&miInfo);
if(miInfo.hSubMenu!=NULL)
{
miInfo.hSubMenu=CopyPopupMenu(miInfo.hSubMenu);
}
VERIFY(::InsertMenuItem(hMenu,nIndex,TRUE,&miInfo));
sText.ReleaseBuffer();
}
return hMenu;
}
BOOL COXBitmapMenuOrganizer::FindPopupMenuPath(HMENU hPopupMenu,
HMENU hParentMenu,
CArray<int,int>& arrPath)
{
ASSERT(hPopupMenu!=NULL);
ASSERT(::IsMenu(hPopupMenu));
ASSERT(hParentMenu!=NULL);
ASSERT(::IsMenu(hParentMenu));
int nItemCount=::GetMenuItemCount(hParentMenu);
for(int nIndex=0; nIndex<nItemCount; nIndex++)
{
HMENU hSubmenu=::GetSubMenu(hParentMenu,nIndex);
if(hSubmenu==hPopupMenu ||
(hSubmenu!=NULL && FindPopupMenuPath(hPopupMenu,hSubmenu,arrPath)))
{
arrPath.InsertAt(0,nIndex);
return TRUE;
}
}
return FALSE;
}
LRESULT CALLBACK COXBitmapMenuOrganizer::
MenuMouseHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
#if defined (_WINDLL)
#if defined (_AFXDLL)
AFX_MANAGE_STATE(AfxGetAppModuleState());
#else
AFX_MANAGE_STATE(AfxGetStaticModuleState());
#endif
#endif
TRACE(_T("COXBitmapMenuOrganizer::MenuMouseHookProc code: %0X, wParam: %0X, lParam: %0X \n"));
ASSERT(g_pfnOldMouseHookProc!=NULL);
if(nCode<0)
{
// have to call the default implementation
return ::CallNextHookEx(g_pfnOldMouseHookProc,nCode,wParam,lParam);
}
if(wParam!=WM_LBUTTONDOWN && wParam!=WM_RBUTTONDOWN &&
wParam!=WM_LBUTTONUP && wParam!=WM_RBUTTONUP &&
wParam!=WM_LBUTTONDBLCLK && wParam!=WM_RBUTTONDBLCLK)
{
// have to call the default implementation
return ::CallNextHookEx(g_pfnOldMouseHookProc,nCode,wParam,lParam);
}
COXBitmapMenuOrganizer* pBMOrganizer=
COXBitmapMenuOrganizer::FindOrganizer(AfxGetMainWnd()->GetSafeHwnd());
ASSERT(pBMOrganizer!=NULL);
ASSERT(pBMOrganizer->IsShowOnlyRecentlyUsedItems());
DWORD dwMessagePos=::GetMessagePos();
POINTS points=MAKEPOINTS(dwMessagePos);
CPoint ptLast(points.x,points.y);
CWnd* pWnd=CWnd::WindowFromPoint(ptLast);
ASSERT(pWnd!=NULL);
// find if pWnd is on of the windows that host popup menus
POSITION pos=pBMOrganizer->m_mapPopupMenuWindows.GetStartPosition();
while(pos!=NULL)
{
HMENU hMenu=NULL;
HWND hWnd=NULL;
pBMOrganizer->m_mapPopupMenuWindows.GetNextAssoc(pos,hMenu,hWnd);
ASSERT(hMenu!=NULL);
ASSERT(hWnd!=NULL);
if(pWnd->GetSafeHwnd()==hWnd)
{
ASSERT(::IsMenu(hMenu));
// find the menu in the trace array
BOOL bFound=FALSE;
int nIndex=0;
for(nIndex=0;
nIndex<pBMOrganizer->m_arrPopupMenusTrace.GetSize(); nIndex++)
{
if(pBMOrganizer->m_arrPopupMenusTrace[nIndex].m_hPopupMenu==hMenu)
{
bFound=TRUE;
break;
}
}
ASSERT(bFound);
if(pBMOrganizer->m_nActivePopupMenuCount>nIndex+1)
{
BOOL bFoundPopupMenuToClose=FALSE;
for(int nIndexPopupWnd=nIndex+1;
nIndexPopupWnd<pBMOrganizer->m_arrPopupMenusTrace.GetSize();
nIndexPopupWnd++)
{
// try to find and close the remaining popup menus
HWND hWnd=NULL;
if(pBMOrganizer->m_mapPopupMenuWindows.Lookup(pBMOrganizer->
m_arrPopupMenusTrace[nIndexPopupWnd].m_hPopupMenu,hWnd))
{
if(::IsWindow(hWnd))
{
::SendMessage(hWnd,WM_KEYDOWN,VK_ESCAPE,0x00010001);
}
bFoundPopupMenuToClose=TRUE;
}
}
if(bFoundPopupMenuToClose)
{
pBMOrganizer->m_nActivePopupMenuCount=nIndex+1;
}
}
// check if "Show All items" menu item has been clicked
int nMenuItemIndex=::MenuItemFromPoint(hWnd,hMenu,ptLast);
if(nMenuItemIndex!=-1)
{
int nCmdID=::GetMenuItemID(hMenu,nMenuItemIndex);
switch(nCmdID)
{
case ID_OX_SHOWALLITEMS:
{
if(wParam!=WM_LBUTTONDOWN && wParam!=WM_RBUTTONDOWN)
{
pBMOrganizer->m_pFrameWnd->PostMessage(WM_COMMAND,
MAKEWPARAM(ID_OX_SHOWALLITEMS,0));
}
// modicication Manfred Drasch - return removed
// return 1;
}
}
}
}
}
return ::CallNextHookEx(g_pfnOldMouseHookProc,nCode,wParam,lParam);
}
LRESULT CALLBACK COXBitmapMenuOrganizer::
MenuKeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
#if defined (_WINDLL)
#if defined (_AFXDLL)
AFX_MANAGE_STATE(AfxGetAppModuleState());
#else
AFX_MANAGE_STATE(AfxGetStaticModuleState());
#endif
#endif
ASSERT(g_pfnOldKeyboardHookProc!=NULL);
// v9.3 update 01 modification - removed by Manfred Drasch
// avoid crash with return over arrow menu item
// if(nCode<0)
// {
// // have to call the default implementation
// return ::CallNextHookEx(g_pfnOldKeyboardHookProc,nCode,wParam,lParam);
// }
//
// if(wParam!=VK_RETURN)
// {
// // have to call the default implementation
// return ::CallNextHookEx(g_pfnOldKeyboardHookProc,nCode,wParam,lParam);
// }
//
// COXBitmapMenuOrganizer* pBMOrganizer=
// COXBitmapMenuOrganizer::FindOrganizer(AfxGetMainWnd()->GetSafeHwnd());
// ASSERT(pBMOrganizer!=NULL);
// ASSERT(pBMOrganizer->IsShowOnlyRecentlyUsedItems());
//
// CWnd* pWnd=CWnd::GetDesktopWindow()->GetTopWindow();
// ASSERT(pWnd!=NULL);
// // find if pWnd is on of the windows that host popup menus
// POSITION pos=pBMOrganizer->m_mapPopupMenuWindows.GetStartPosition();
// while(pos!=NULL)
// {
// HMENU hMenu=NULL;
// HWND hWnd=NULL;
// pBMOrganizer->m_mapPopupMenuWindows.GetNextAssoc(pos,hMenu,hWnd);
// ASSERT(hMenu!=NULL);
// ASSERT(hWnd!=NULL);
// if(pWnd->GetSafeHwnd()==hWnd)
// {
// MENUITEMINFO miInfo={ sizeof(MENUITEMINFO) };
// miInfo.fMask=MIIM_ID|MIIM_STATE;
// VERIFY(::GetMenuItemInfo(hMenu,::GetMenuItemCount(hMenu)-1,TRUE,&miInfo));
// if(miInfo.wID==ID_OX_SHOWALLITEMS && (miInfo.fState&MFS_HILITE))
// {
// if((lParam&0xe0000000)==0)
// {
// pBMOrganizer->m_pFrameWnd->PostMessage(WM_COMMAND,
// MAKEWPARAM(ID_OX_SHOWALLITEMS,0));
// }
//
// return 1;
// }
// }
// }
//
// end modification Manfred Drasch
return ::CallNextHookEx(g_pfnOldKeyboardHookProc,nCode,wParam,lParam);
}