// ==========================================================================
// Class Implementation : COXBitmapMenu
// ==========================================================================
// Source file : OXBitmapMenu.cpp
// 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"
#pragma warning(disable : 4706)
#include <multimon.h>
#include "OXBitmapMenu.h"
#include "OXBitmapMenuOrganizer.h"
#include "OXSkins.h"
#include "OXCoolToolBar.h"
#include "OXMenuBar.h"
#ifdef OX_CUSTOMIZE_COMMANDS
#include "OXDragDropCommands.h"
#endif // OX_CUSTOMIZE_COMMANDS
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#endif
/////////////////////////////////////////////////////////
IMPLEMENT_DYNAMIC(COXBitmapMenuPopupWnd,CWnd)
COXBitmapMenuPopupWnd::COXBitmapMenuPopupWnd() :
m_pBitmapMenu(NULL),
m_nCheckForDragDropEventTimerID(0)
{
}
COXBitmapMenuPopupWnd::~COXBitmapMenuPopupWnd()
{
ResetPopupMenu();
}
BEGIN_MESSAGE_MAP(COXBitmapMenuPopupWnd,CWnd)
//{{AFX_MSG_MAP(COXBitmapMenuPopupWnd)
ON_WM_RBUTTONUP()
ON_WM_LBUTTONDOWN()
ON_WM_MBUTTONDOWN()
ON_WM_RBUTTONDOWN()
ON_WM_PAINT()
ON_WM_MOUSEACTIVATE()
ON_WM_SETTINGCHANGE()
ON_WM_TIMER()
ON_WM_MOUSEMOVE()
ON_WM_NCPAINT()
//}}AFX_MSG_MAP
// handle drag'n'drop messages
ON_MESSAGE(SHBDTM_DRAGENTER, OnDragEnter)
ON_MESSAGE(SHBDTM_DRAGLEAVE, OnDragLeave)
ON_MESSAGE(SHBDTM_DRAGOVER, OnDragOver)
ON_MESSAGE(SHBDTM_DROP, OnDrop)
// handle advanced customization commands
ON_COMMAND(ID_OXCUSTBM_DELETE,OnCustBMDelete)
ON_COMMAND(ID_OXCUSTBM_APPEARANCE,OnCustBMAppearance)
ON_COMMAND(ID_OXCUSTBM_SEPARATOR_BEFORE,OnCustBMSeparatorBefore)
ON_COMMAND(ID_OXCUSTBM_SEPARATOR_AFTER,OnCustBMSeparatorAfter)
ON_COMMAND(ID_OXCUSTBM_RECENTLY_USED,OnCustBMRecentlyUsed)
END_MESSAGE_MAP()
void COXBitmapMenuPopupWnd::OnLButtonDown(UINT nFlags, CPoint point)
{
TRACE(_T("COXBitmapMenuPopupWnd::OnLButtonDown\n"));
COXBitmapMenu* pMenu=GetBitmapMenu();
if(m_nCheckForDragDropEventTimerID==0 &&
pMenu!=NULL && pMenu->IsInCustomizationMode())
{
int nItemIndex=pMenu->HitTest(&point);
if(nItemIndex>=0 && nItemIndex<(int)pMenu->GetMenuItemCount())
{
pMenu->SetCustomizedItem(nItemIndex);
}
else
{
pMenu->SetCustomizedItem(-1);
}
m_nCheckForDragDropEventTimerID=SetTimer(IDT_OXCHECKFORDRAGDROPEVENT,
ID_OXCHECKFORDRAGDROPEVENT_DELAY,NULL);
ASSERT(m_nCheckForDragDropEventTimerID!=0);
return;
}
CWnd::OnLButtonDown(nFlags,point);
}
void COXBitmapMenuPopupWnd::OnMButtonDown(UINT nFlags, CPoint point)
{
COXBitmapMenu* pMenu=GetBitmapMenu();
if(pMenu!=NULL && pMenu->IsInCustomizationMode())
{
int nItemIndex=pMenu->HitTest(&point);
if(nItemIndex>=0 && nItemIndex<(int)pMenu->GetMenuItemCount())
{
pMenu->SetCustomizedItem(nItemIndex);
}
else
{
pMenu->SetCustomizedItem(-1);
}
return;
}
CWnd::OnMButtonDown(nFlags,point);
}
void COXBitmapMenuPopupWnd::OnRButtonDown(UINT nFlags, CPoint point)
{
COXBitmapMenu* pMenu=GetBitmapMenu();
if(pMenu!=NULL && pMenu->IsInCustomizationMode())
{
int nItemIndex=pMenu->HitTest(&point);
if(nItemIndex>=0 && nItemIndex<(int)pMenu->GetMenuItemCount())
{
pMenu->SetCustomizedItem(nItemIndex);
}
else
{
pMenu->SetCustomizedItem(-1);
}
return;
}
CWnd::OnRButtonDown(nFlags,point);
}
void COXBitmapMenuPopupWnd::OnRButtonUp(UINT nFlags, CPoint point)
{
COXBitmapMenu* pMenu=GetBitmapMenu();
if(pMenu!=NULL && pMenu->IsInCustomizationMode())
{
int nCustomizedItemIndex=pMenu->GetCustomizedItem();
if(nCustomizedItemIndex!=-1)
{
ClientToScreen(&point);
pMenu->DisplayCustomizeItemContextMenu(nCustomizedItemIndex,point);
return;
}
}
CWnd::OnRButtonUp(nFlags,point);
}
void COXBitmapMenuPopupWnd::OnMouseMove(UINT nFlags, CPoint point)
{
if(m_nCheckForDragDropEventTimerID!=0 && ::GetKeyState(VK_LBUTTON)>=0)
{
KillTimer(m_nCheckForDragDropEventTimerID);
m_nCheckForDragDropEventTimerID=0;
}
CWnd::OnMouseMove(nFlags,point);
}
LONG COXBitmapMenuPopupWnd::OnDragEnter(WPARAM wParam, LPARAM lParam)
{
COXBitmapMenu* pMenu=GetBitmapMenu();
if(pMenu!=NULL && pMenu->IsInCustomizationMode())
{
// lParam is the pointer to SHBDROPTARGETACTION structure
LPSHBDROPTARGETACTION pSHBDTAction=(LPSHBDROPTARGETACTION)lParam;
ASSERT(pSHBDTAction!=NULL);
ASSERT(pSHBDTAction->pWnd);
ASSERT(pSHBDTAction->pWnd->GetSafeHwnd()==GetSafeHwnd());
return pMenu->OnDragOver(wParam,lParam);
}
return (LONG)FALSE;
}
LONG COXBitmapMenuPopupWnd::OnDragOver(WPARAM wParam, LPARAM lParam)
{
COXBitmapMenu* pMenu=GetBitmapMenu();
if(pMenu!=NULL && pMenu->IsInCustomizationMode())
{
// lParam is the pointer to SHBDROPTARGETACTION structure
LPSHBDROPTARGETACTION pSHBDTAction=(LPSHBDROPTARGETACTION)lParam;
ASSERT(pSHBDTAction!=NULL);
ASSERT(pSHBDTAction->pWnd);
ASSERT(pSHBDTAction->pWnd->GetSafeHwnd()==GetSafeHwnd());
return pMenu->OnDragOver(wParam,lParam);
}
return (LONG)FALSE;
}
LONG COXBitmapMenuPopupWnd::OnDragLeave(WPARAM wParam, LPARAM lParam)
{
COXBitmapMenu* pMenu=GetBitmapMenu();
if(pMenu!=NULL && pMenu->IsInCustomizationMode())
{
// lParam is the pointer to SHBDROPTARGETACTION structure
LPSHBDROPTARGETACTION pSHBDTAction=(LPSHBDROPTARGETACTION)lParam;
ASSERT(pSHBDTAction!=NULL);
ASSERT(pSHBDTAction->pWnd);
ASSERT(pSHBDTAction->pWnd->GetSafeHwnd()==GetSafeHwnd());
return pMenu->OnDragLeave(wParam,lParam);
}
return (LONG)FALSE;
}
LONG COXBitmapMenuPopupWnd::OnDrop(WPARAM wParam, LPARAM lParam)
{
COXBitmapMenu* pMenu=GetBitmapMenu();
if(pMenu!=NULL && pMenu->IsInCustomizationMode())
{
// lParam is the pointer to SHBDROPTARGETACTION structure
LPSHBDROPTARGETACTION pSHBDTAction=(LPSHBDROPTARGETACTION)lParam;
ASSERT(pSHBDTAction!=NULL);
ASSERT(pSHBDTAction->pWnd);
ASSERT(pSHBDTAction->pWnd->GetSafeHwnd()==GetSafeHwnd());
return pMenu->OnDrop(wParam,lParam);
}
return (LONG)FALSE;
}
void COXBitmapMenuPopupWnd::OnCustBMDelete()
{
COXBitmapMenu* pMenu=GetBitmapMenu();
if(pMenu!=NULL && pMenu->IsInCustomizationMode())
{
pMenu->OnCustBMDelete();
}
}
void COXBitmapMenuPopupWnd::OnCustBMAppearance()
{
COXBitmapMenu* pMenu=GetBitmapMenu();
if(pMenu!=NULL && pMenu->IsInCustomizationMode())
{
pMenu->OnCustBMAppearance();
}
}
void COXBitmapMenuPopupWnd::OnCustBMSeparatorBefore()
{
COXBitmapMenu* pMenu=GetBitmapMenu();
if(pMenu!=NULL && pMenu->IsInCustomizationMode())
{
pMenu->OnCustBMSeparatorBefore();
}
}
void COXBitmapMenuPopupWnd::OnCustBMSeparatorAfter()
{
COXBitmapMenu* pMenu=GetBitmapMenu();
if(pMenu!=NULL && pMenu->IsInCustomizationMode())
{
pMenu->OnCustBMSeparatorAfter();
}
}
void COXBitmapMenuPopupWnd::OnCustBMRecentlyUsed()
{
COXBitmapMenu* pMenu=GetBitmapMenu();
if(pMenu!=NULL && pMenu->IsInCustomizationMode())
{
pMenu->OnCustBMRecentlyUsed();
}
}
void COXBitmapMenuPopupWnd::OnPaint()
{
CPaintDC dc(this);
int nSavedDC=dc.SaveDC();
ASSERT(nSavedDC!=0);
dc.SetTextColor(::GetSysColor(COLOR_MENUTEXT));
dc.SelectObject(&m_fontMenu);
COXBitmapMenu* pMenu=GetBitmapMenu();
if(pMenu!=NULL)
{
ASSERT((int)pMenu->GetMenuItemCount()==m_arrItemRects.GetSize());
MENUITEMINFO mii={ sizeof(mii) };
mii.fMask=MIIM_DATA;
DRAWITEMSTRUCT dis;
dis.CtlType=ODT_MENU;
dis.hDC=dc.GetSafeHdc();
dis.itemAction=ODA_DRAWENTIRE;
dis.CtlID=0;
dis.itemState=0;
dis.hwndItem=(HWND)pMenu->GetSafeHmenu();
for(int nIndex=0; nIndex<m_arrItemRects.GetSize(); nIndex++)
{
dis.itemID=pMenu->GetMenuItemID(nIndex);
dis.rcItem=m_arrItemRects[nIndex];
VERIFY(::GetMenuItemInfo(pMenu->GetSafeHmenu(),nIndex,TRUE,&mii));
dis.itemData=mii.dwItemData;
pMenu->DrawItem(&dis);
}
}
VERIFY(dc.RestoreDC(nSavedDC));
}
int COXBitmapMenuPopupWnd::OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest,
UINT message)
{
UNREFERENCED_PARAMETER(pDesktopWnd);
UNREFERENCED_PARAMETER(nHitTest);
UNREFERENCED_PARAMETER(message);
return MA_NOACTIVATE;
}
void COXBitmapMenuPopupWnd::OnSettingChange(UINT uFlags, LPCTSTR lpszSection)
{
UpdateMenuMetrics();
OnMenuChanged();
CWnd::OnSettingChange(uFlags, lpszSection);
}
void COXBitmapMenuPopupWnd::OnTimer(UINT nIDEvent)
{
if((int)nIDEvent==m_nCheckForDragDropEventTimerID)
{
KillTimer(m_nCheckForDragDropEventTimerID);
m_nCheckForDragDropEventTimerID=0;
if(::IsWindow(GetSafeHwnd()))
{
// do drag and drop
//
COXBitmapMenu* pMenu=GetBitmapMenu();
if(pMenu!=NULL && pMenu->IsInCustomizationMode())
{
if(::GetKeyState(VK_LBUTTON)<0)
{
pMenu->OnBeginDragDrop(pMenu->GetCustomizedItem());
}
}
//
////////////////////////////////////
}
return;
}
CWnd::OnTimer(nIDEvent);
}
BOOL COXBitmapMenuPopupWnd::TrackPopupMenu(COXBitmapMenu* pMenu, UINT nFlags,
int x, int y, CWnd* pWnd)
{
ASSERT(pMenu!=NULL);
m_pBitmapMenu=pMenu;
COXBitmapMenu* pBitmapMenu=GetBitmapMenu();
pBitmapMenu->SetPopupWnd(this);
if(!::IsWindow(GetSafeHwnd()))
{
if(!CreateEx(WS_EX_DLGMODALFRAME,AfxRegisterWndClass(
CS_SAVEBITS|CS_DBLCLKS,0,(HBRUSH)(COLOR_BTNFACE+1),0),_T(""),
WS_POPUP,m_rectWindow,pWnd,0,NULL))
{
return FALSE;
}
}
// register OLE Drag'n'Drop
COleDropTarget* pOleDropTarget=pBitmapMenu->GetDropTarget();
ASSERT(pOleDropTarget!=NULL);
pOleDropTarget->Revoke();
if(!pOleDropTarget->Register(this))
{
TRACE(_T("COXBitmapMenuPopupWnd::Create: failed to register the control with COleDropTarget. You've probably forgotten to initialize OLE libraries using AfxOleInit function\n"));
}
pBitmapMenu->SetCutomizationMode(TRUE,pWnd->GetSafeHwnd());
// update info about the font used to display the menu
UpdateMenuMetrics();
// calculate the rectangles for the menu items and for the popup menu itself
VERIFY(CalcLayout(nFlags,x,y));
SetWindowPos(&wndTop,m_rectWindow.left,m_rectWindow.top,m_rectWindow.Width(),
m_rectWindow.Height(),SWP_NOACTIVATE|SWP_SHOWWINDOW);
ShowWindow(SW_SHOWNA);
return TRUE;
}
void COXBitmapMenuPopupWnd::ResetPopupMenu()
{
COXBitmapMenu* pMenu=GetBitmapMenu();
if(pMenu!=NULL)
{
if(!pMenu->IsDragDropOwner())
{
pMenu->SetCustomizedItem(-1);
pMenu->SetPopupWnd(NULL);
m_pBitmapMenu=NULL;
}
}
if(::IsWindow(GetSafeHwnd()))
{
ShowWindow(SW_HIDE);
}
}
BOOL COXBitmapMenuPopupWnd::CalcLayout(UINT nFlags, int x, int y)
{
COXBitmapMenu* pMenu=GetBitmapMenu();
if(pMenu==NULL)
{
return FALSE;
}
m_arrItemRects.RemoveAll();
m_rectWindow.SetRectEmpty();
int nWidth=0;
int nHeight=0;
int nIndex=0;
for(nIndex=0; nIndex<(int)pMenu->GetMenuItemCount(); nIndex++)
{
MENUITEMINFO mii={ sizeof(mii) };
mii.fMask=MIIM_DATA;
VERIFY(::GetMenuItemInfo(pMenu->GetSafeHmenu(),nIndex,TRUE,&mii));
MEASUREITEMSTRUCT mis;
mis.CtlType=ODT_MENU;
mis.itemData=mii.dwItemData;
mis.itemID=pMenu->GetMenuItemID(nIndex);
mis.itemHeight=0;
mis.itemWidth=0;
pMenu->MeasureItem(&mis);
CRect rect(0,nHeight,mis.itemWidth,nHeight+mis.itemHeight);
m_arrItemRects.Add(rect);
nHeight+=mis.itemHeight;
if(nWidth<(int)mis.itemWidth)
nWidth=mis.itemWidth;
}
if(nWidth==0 && nHeight==0)
{
nWidth=ID_OXBITMAPMENUPOPUPWND_DEFAULT_WIDTH;
nHeight=ID_OXBITMAPMENUPOPUPWND_DEFAULT_HEIGHT;
}
m_rectWindow.top=y;
switch(nFlags)
{
case TPM_CENTERALIGN:
m_rectWindow.left=x-nWidth/2;
break;
case TPM_LEFTALIGN:
m_rectWindow.left=x;
break;
case TPM_RIGHTALIGN:
m_rectWindow.left=x-nWidth;
break;
}
m_rectWindow.right=m_rectWindow.left+nWidth;
m_rectWindow.bottom=m_rectWindow.top+nHeight;
CRect rectCopy=m_rectWindow;
CalcWindowRect(m_rectWindow);
CSize szOffset(rectCopy.left-m_rectWindow.left,rectCopy.top-m_rectWindow.top);
m_rectWindow.OffsetRect(szOffset.cx,szOffset.cy);
m_rectWindow.InflateRect(0,0,2*szOffset.cx,0);
nWidth+=2*szOffset.cx;
// adjust rectangles for items
for(nIndex=0; nIndex<m_arrItemRects.GetSize(); nIndex++)
{
CRect& rect=m_arrItemRects[nIndex];
if(rect.Width()<nWidth)
rect.right=rect.left+nWidth;
}
return TRUE;
}
void COXBitmapMenuPopupWnd::UpdateMenuMetrics()
{
if((HFONT)m_fontMenu!=NULL)
m_fontMenu.DeleteObject();
// Menu font, height and color
NONCLIENTMETRICS ncm={ sizeof(ncm) };
SystemParametersInfo(SPI_GETNONCLIENTMETRICS,sizeof(ncm),&ncm,0);
VERIFY(m_fontMenu.CreateFontIndirect(&ncm.lfMenuFont));
}
void COXBitmapMenuPopupWnd::OnMenuChanged()
{
ASSERT(GetBitmapMenu()!=NULL);
ASSERT(::IsWindow(GetSafeHwnd()));
CRect rect;
GetWindowRect(rect);
CPoint ptStart=rect.TopLeft();
GetBitmapMenu()->CalcExtents();
VERIFY(CalcLayout(TPM_LEFTALIGN,ptStart.x,ptStart.y));
if(IsWindowVisible())
{
SetWindowPos(&wndTop,m_rectWindow.left,m_rectWindow.top,m_rectWindow.Width(),
m_rectWindow.Height(),SWP_NOACTIVATE|SWP_SHOWWINDOW);
RedrawWindow();
}
else
{
ResetPopupMenu();
}
}
void COXBitmapMenuPopupWnd::RedrawItem(int nIndex)
{
ASSERT(GetBitmapMenu()!=NULL);
ASSERT(::IsWindow(GetSafeHwnd()));
ASSERT(nIndex>=0 && nIndex<m_arrItemRects.GetSize());
CRect rect;
rect=m_arrItemRects[nIndex];
RedrawWindow(rect);
}
///////////////////////////////////////////////////////
// COXShadowedItemWnd
COXShadowedItemWnd::COXShadowedItemWnd(COXCoolToolBar* pCoolToolbar, int iMenuItem, UINT nPosFlags)
{
m_pCoolToolbar = pCoolToolbar;
m_iMenuItem = iMenuItem;
m_nPosFlags = nPosFlags;
}
COXShadowedItemWnd::~COXShadowedItemWnd()
{
}
BEGIN_MESSAGE_MAP(COXShadowedItemWnd, CWnd)
//{{AFX_MSG_MAP(COXShadowedItemWnd)
ON_WM_PAINT()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
WNDPROC COXBitmapMenu::m_origWndProc = NULL;
IMPLEMENT_DYNAMIC(COXBitmapMenu, CMenu)
COXMenuSkin* COXBitmapMenu::m_pMenuSkin = NULL;
COXBitmapMenu::COXBitmapMenu()
:
m_nBitmapExtent(0),
m_nTextHeight(0),
m_nAcceleratorExtent(0),
m_nStringExtent(0),
m_nCustomizedItemIndex(-1),
m_bCutomizable(FALSE),
m_bInCutomizationMode(FALSE),
m_bDragDropOwner(FALSE),
m_bDragDropOperation(FALSE),
m_hWndCustomizeOrganizer(NULL),
m_nInsertMarkIndex(-1),
m_pPopupWnd(NULL),
m_rectDropDownItem(0, 0, 0, 0)
{
// Sublass the menus
RegisterWindowClass(AfxGetInstanceHandle());
}
COXBitmapMenu::~COXBitmapMenu()
{
m_KeyAccessMap.RemoveAll();
COXItemInfo* pItemInfo;
while(!m_ItemInfoList.IsEmpty())
{
pItemInfo=m_ItemInfoList.RemoveHead();
delete pItemInfo;
pItemInfo = NULL;
}
TRACE(_T("\n"));
// delete the classic skin
if (m_pMenuSkin != NULL)
{
delete m_pMenuSkin;
m_pMenuSkin = NULL;
}
COleDropTarget* pOleDropTarget=GetDropTarget();
ASSERT(pOleDropTarget!=NULL);
pOleDropTarget->Revoke();
}
void COXBitmapMenu::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
ASSERT(m_hMenu!=NULL);
ASSERT(lpDrawItemStruct != NULL);
ASSERT(lpDrawItemStruct->CtlType == ODT_MENU);
UINT nState=lpDrawItemStruct->itemState;
CRect itemRect(lpDrawItemStruct->rcItem);
CRect buttonRect(0,0,0,0);
CRect imageRect(0,0,0,0);
CRect text1Rect(0,0,0,0);
CRect text2Rect(0,0,0,0);
CDC dc;
dc.Attach(lpDrawItemStruct->hDC);
COXItemInfo* pItemInfo=(COXItemInfo*)lpDrawItemStruct->itemData;
ASSERT(AfxIsValidAddress(pItemInfo, sizeof(COXItemInfo)));
COXImageInfo* pImageInfo=pItemInfo->GetImageInfo();
CString sText=pItemInfo->GetText();
if(lpDrawItemStruct->itemID!=0 && lpDrawItemStruct->itemID!=0xffff)
{
// Compute the space for each menu item part
DistributeSpace(
nState,pImageInfo,itemRect,buttonRect,imageRect,text1Rect,text2Rect);
}
COXBitmapMenuOrganizer* pOrganizer=
COXBitmapMenuOrganizer::FindOrganizer(AfxGetMainWnd()->GetSafeHwnd());
ASSERT(pOrganizer!=NULL);
BOOL bBefore=TRUE;
CPoint ptTest=itemRect.CenterPoint();
int nItemIndex=HitTest(&ptTest,&bBefore);
if(pOrganizer->IsShowOnlyRecentlyUsedItems() &&
!pOrganizer->IsRecentlyUsed(this,nItemIndex))
{
nState|=OXODS_HIDDEN;
if(nItemIndex>0 && pOrganizer->IsRecentlyUsed(this,nItemIndex-1))
{
nState|=OXODS_HIDDENFIRST;
}
if(nItemIndex<(int)GetMenuItemCount()-1 &&
pOrganizer->IsRecentlyUsed(this,nItemIndex+1))
{
nState|=OXODS_HIDDENLAST;
}
}
// Draw every part of the menu item
if(lpDrawItemStruct->itemID==0 || lpDrawItemStruct->itemID==0xffff)
{
DrawSeparator(&dc,itemRect);
}
else if(IsPopupItem(lpDrawItemStruct->itemID))
{
DrawSubmenuItem(&dc,nState,sText,pImageInfo,
itemRect,buttonRect,text1Rect,text2Rect);
}
else
{
DrawBackground(&dc,nState,pImageInfo,itemRect,buttonRect);
DrawButton(&dc,nState,pImageInfo,buttonRect);
DrawImage(&dc,nState,pImageInfo,imageRect);
if((((int)lpDrawItemStruct->itemID)&0x0000ffff)==ID_OX_SHOWALLITEMS)
{
ASSERT(!IsInCustomizationMode());
DrawExpansionItem(&dc,itemRect,nState);
}
else
{
DrawText(&dc,nState,sText,text1Rect,text2Rect);
}
}
// draw customized item
int nCustomizedItem=GetCustomizedItem();
if(nCustomizedItem!=-1 &&
GetMenuItemID(nCustomizedItem)==lpDrawItemStruct->itemID)
{
CPoint pt=itemRect.CenterPoint();
if(HitTest(&pt)==nCustomizedItem)
{
DrawCustomized(&dc,itemRect);
}
}
// draw insert mark
int nInsertMark=GetInsertMark();
if(nInsertMark!=-1)
{
ASSERT(nInsertMark>=0 && nInsertMark<=(int)GetMenuItemCount());
BOOL bBefore=(nInsertMark<(int)GetMenuItemCount());
if(!bBefore)
nInsertMark--;
CPoint pt=itemRect.CenterPoint();
if(HitTest(&pt)==nInsertMark)
{
DrawInsertMark(&dc,itemRect,bBefore);
}
}
dc.Detach();
}
void COXBitmapMenu::DistributeSpace(UINT nState,
COXImageInfo* pImageInfo,
CRect itemRect,
CRect& buttonRect,
CRect& imageRect,
CRect& text1Rect,
CRect& text2Rect)
{
GetMenuSkin()->DistributeSpace(nState, pImageInfo, itemRect, buttonRect, imageRect,
text1Rect, text2Rect, this);
}
HBRUSH COXBitmapMenu::HBrushDitherCreate(COLORREF rgbFace, COLORREF rgbHilight)
{
struct //BITMAPINFO with 16 colors
{
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[16];
} bmi;
HBRUSH hBrush=NULL;
DWORD patGray[8];
HDC hDC;
HBITMAP hBmp;
static COLORREF rgbFaceOld=0xFFFFFFFF; //Initially impossible
static COLORREF rgbHilightOld=0xFFFFFFFF; //Initially impossible
/*
* We're going to create an 8*8 brush for PatBlt using the
* face color and highlight color.
*/
bmi.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth=8;
bmi.bmiHeader.biHeight=8;
bmi.bmiHeader.biPlanes=1;
bmi.bmiHeader.biBitCount=1;
bmi.bmiHeader.biCompression=BI_RGB;
bmi.bmiHeader.biSizeImage=0;
bmi.bmiHeader.biXPelsPerMeter=0;
bmi.bmiHeader.biYPelsPerMeter=0;
bmi.bmiHeader.biClrUsed=0;
bmi.bmiHeader.biClrImportant=0;
bmi.bmiColors[0].rgbBlue=GetBValue(rgbFace);
bmi.bmiColors[0].rgbGreen=GetGValue(rgbFace);
bmi.bmiColors[0].rgbRed=GetRValue(rgbFace);
bmi.bmiColors[0].rgbReserved=0;
bmi.bmiColors[1].rgbBlue=GetBValue(rgbHilight);
bmi.bmiColors[1].rgbGreen=GetGValue(rgbHilight);
bmi.bmiColors[1].rgbRed=GetRValue(rgbHilight);
bmi.bmiColors[1].rgbReserved=0;
//Create the byte array for CreateDIBitmap.
patGray[6]=patGray[4]=patGray[2]=patGray[0]=0x5555AAAAL;
patGray[7]=patGray[5]=patGray[3]=patGray[1]=0xAAAA5555L;
//Create the bitmap
hDC=::GetDC(NULL);
hBmp=::CreateDIBitmap(hDC,&bmi.bmiHeader,CBM_INIT,patGray,
(LPBITMAPINFO)&bmi,DIB_RGB_COLORS);
::ReleaseDC(NULL,hDC);
//Create the brush from the bitmap
if(NULL!=hBmp)
{
hBrush=CreatePatternBrush(hBmp);
DeleteObject(hBmp);
}
return hBrush;
}
void COXBitmapMenu::DrawBackground(CDC* pDC, UINT nState, COXImageInfo* pImageInfo,
CRect itemRect, CRect buttonRect)
{
GetMenuSkin()->DrawBackground(pDC, nState, pImageInfo, itemRect, buttonRect, this);
}
void COXBitmapMenu::DrawButton(CDC* pDC, UINT nState, COXImageInfo* pImageInfo,
CRect buttonRect)
{
GetMenuSkin()->DrawButton(pDC, nState, pImageInfo, buttonRect, this);
}
void COXBitmapMenu::DrawImage(CDC* pDC, UINT nState, COXImageInfo* pImageInfo,
CRect imageRect)
{
GetMenuSkin()->DrawImage(pDC, nState, pImageInfo, imageRect, this);
}
void COXBitmapMenu::DrawText(CDC* pDC, UINT nState,
CString sText, CRect text1Rect, CRect text2Rect)
{
GetMenuSkin()->DrawText(pDC, nState, sText, text1Rect, text2Rect, this);
}
void COXBitmapMenu::DrawSeparator(CDC* pDC, CRect itemRect)
{
GetMenuSkin()->DrawSeparator(pDC, itemRect, this);
}
void COXBitmapMenu::DrawCustomized(CDC* pDC, CRect itemRect)
{
GetMenuSkin()->DrawCustomized(pDC, itemRect, this);
}
void COXBitmapMenu::DrawInsertMark(CDC* pDC, CRect itemRect, BOOL bBefore)
{
GetMenuSkin()->DrawInsertMark(pDC, itemRect, bBefore, this);
}
void COXBitmapMenu::DrawSubmenuItem(CDC* pDC, UINT nState, CString sText,
COXImageInfo* pImageInfo,
CRect itemRect, CRect buttonRect,
CRect text1Rect, CRect text2Rect)
{
GetMenuSkin()->DrawSubmenuItem(pDC, nState, sText, pImageInfo, itemRect, buttonRect,
text1Rect, text2Rect, this);
}
void COXBitmapMenu::DrawExpansionItem(CDC* pDC, CRect itemRect, UINT nState)
{
GetMenuSkin()->DrawExpansionItem(pDC, itemRect, nState, this);
}
void COXBitmapMenu::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
OXDIMENSIONCONSTANTS& oxdc = GetMenuSkin()->GetDimentionConstants();
ASSERT(lpMeasureItemStruct != NULL);
COXItemInfo* pItemInfo=(COXItemInfo*)lpMeasureItemStruct->itemData;
if(pItemInfo)
{
ASSERT(AfxIsValidAddress(pItemInfo, sizeof(COXItemInfo)));
COXImageInfo* pImageInfo=pItemInfo->GetImageInfo();
int nImageWidth=0;
int nImageHeight=0;
if(pImageInfo != NULL)
{
IMAGEINFO ii;
::ZeroMemory(&ii, sizeof(ii));
pImageInfo->GetImageList()->GetImageInfo(pImageInfo->GetIndex(),&ii);
nImageWidth=ii.rcImage.right - ii.rcImage.left + 2;
nImageHeight=ii.rcImage.bottom - ii.rcImage.top + 2;
}
lpMeasureItemStruct->itemWidth=
oxdc.m_nGapLeftBitmap+m_nBitmapExtent+oxdc.m_nGapBitmapText+
m_nStringExtent+(m_nAcceleratorExtent ? oxdc.m_nGapTextAcclrtr : 0)+
m_nAcceleratorExtent+oxdc.m_nGapAcclrtrRight;
if(lpMeasureItemStruct->itemID==0 || lpMeasureItemStruct->itemID==0xffff)
{
// separator
lpMeasureItemStruct->itemHeight=oxdc.m_nSeparatorHeight;
}
else
{
// item with text
lpMeasureItemStruct->itemHeight=__max(nImageHeight+oxdc.m_nGapVertBitmap,
m_nTextHeight+oxdc.m_nGapVertText);
if ((((int)lpMeasureItemStruct->itemID)&0x0000ffff)==ID_OX_SHOWALLITEMS)
GetMenuSkin()->AdjustExpansionItemHeight(lpMeasureItemStruct->itemHeight, this);
}
}
else if (IsPopupItem(lpMeasureItemStruct->itemID))
lpMeasureItemStruct->itemHeight = m_nTextHeight + oxdc.m_nGapVertText;
}
void COXBitmapMenu::CalcExtents()
{
UINT nItemCount=GetMenuItemCount();
CString sText;
CString sBeforeTab;
CString sAfterTab;
int nTabCharIndex=0;
m_nStringExtent=0;
m_nAcceleratorExtent=0;
m_nBitmapExtent=0;
MENUITEMINFO mii={ sizeof(MENUITEMINFO) };
CFont Font, boldFont;
NONCLIENTMETRICS ncm={ sizeof(NONCLIENTMETRICS) };
COXItemInfo* pItemInfo=NULL;
COXImageInfo* pImageInfo=NULL;
IMAGEINFO ii={ 0 };
VERIFY(SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0));
VERIFY(Font.CreateFontIndirect(&ncm.lfMenuFont));
ncm.lfMenuFont.lfWeight = FW_BOLD; // make the font bold
VERIFY(boldFont.CreateFontIndirect(&ncm.lfMenuFont));
CWnd* pMainWnd=AfxGetThread()->GetMainWnd();
CDC* pDC=pMainWnd->GetDC();
CSize TextExt;
for(UINT nItemIndex=0; nItemIndex < nItemCount; nItemIndex++)
{
CFont* pOldFont;
if (GetDefaultItem(GMDI_USEDISABLED, MF_BYPOSITION) == nItemIndex)
pOldFont = pDC->SelectObject(&boldFont);
else
pOldFont = pDC->SelectObject(&Font);
mii.fMask=MIIM_TYPE|MIIM_DATA|MIIM_SUBMENU;
mii.cch=300;
mii.dwTypeData=sText.GetBuffer(mii.cch);
// ... zero-terminate string
mii.dwTypeData[0]=_T('\0');
::GetMenuItemInfo(GetSafeHmenu(), nItemIndex, TRUE, &mii);
sText.ReleaseBuffer();
if(mii.fType & MFT_SEPARATOR)
continue;
pItemInfo=(COXItemInfo*)(mii.dwItemData);
if(pItemInfo)
{
pImageInfo=pItemInfo->GetImageInfo();
if(pImageInfo)
{
pImageInfo->GetImageList()->GetImageInfo(pImageInfo->GetIndex(),&ii);
m_nBitmapExtent=__max(m_nBitmapExtent, __max(GetMenuSkin()->GetDimentionConstants().m_nMinBitmapWidth,ii.rcImage.right-ii.rcImage.left));
}
sText=pItemInfo->GetText();
}
nTabCharIndex=sText.Find(_T('\t'));
if(nTabCharIndex != -1)
{
sBeforeTab=sText.Left(nTabCharIndex);
sAfterTab=sText.Mid(nTabCharIndex + 1);
}
else
{
sBeforeTab=sText;
if(mii.hSubMenu!=NULL)
sAfterTab=_T("W");
else
sAfterTab.Empty();
}
CRect text1Rect(0,0,0,0);
CRect text2Rect(0,0,0,0);
pDC->DrawText(sBeforeTab, text1Rect, DT_CALCRECT | DT_SINGLELINE);
pDC->DrawText(sAfterTab, text2Rect, DT_CALCRECT | DT_SINGLELINE);
m_nStringExtent=__max(m_nStringExtent, text1Rect.Width());
m_nAcceleratorExtent=__max(m_nAcceleratorExtent, text2Rect.Width());
pDC->SelectObject(pOldFont);
}
TextExt=pDC->GetTextExtent(_T("A"));
m_nTextHeight=TextExt.cy;
pMainWnd->ReleaseDC(pDC);
}
void COXBitmapMenu::AddItemInfo(COXItemInfo* pItemInfo)
{
m_ItemInfoList.AddTail(pItemInfo);
}
/////////////////////////////////////////////////////////////////////////////
// COXBitmapMenu idle update through CBitmapMenuCmdUI class
class OX_CLASS_DECL CBitmapMenuCmdUI : public CCmdUI // class private to this file !
{
public: // re-implementations only
virtual void SetText(LPCTSTR lpszText);
};
void CBitmapMenuCmdUI::SetText(LPCTSTR lpszText)
{
ASSERT(lpszText != NULL);
ASSERT(AfxIsValidString(lpszText));
ASSERT(m_pMenu->IsKindOf(RUNTIME_CLASS(COXBitmapMenu)));
if(m_pMenu != NULL)
{
if(m_pSubMenu != NULL)
return; // don't change popup menus indirectly
MENUITEMINFO mii={ sizeof(mii) };
mii.fMask=MIIM_TYPE|MIIM_DATA;
::GetMenuItemInfo(m_pMenu->GetSafeHmenu(),m_nIndex,TRUE,&mii);
if(mii.fType == MFT_OWNERDRAW)
{
COXItemInfo* pItemInfo=(COXItemInfo*)(mii.dwItemData);
ASSERT(pItemInfo != NULL);
pItemInfo->SetText(lpszText);
}
else
{
CCmdUI::SetText(lpszText);
}
}
}
void COXBitmapMenu::OnUpdateCmdUI(CWnd* pWnd, UINT /*nIndex*/, BOOL bSysMenu)
{
// Code almost entirely copied from CFrameWnd::OnInitPopup
if(bSysMenu)
{
return; // don't support system menu
}
// check the enabled state of various menu items
CBitmapMenuCmdUI state;
state.m_pMenu=this;
ASSERT(state.m_pOther == NULL);
ASSERT(state.m_pParentMenu == NULL);
// determine if menu is popup in top-level menu and set m_pOther to
// it if so (m_pParentMenu == NULL indicates that it is secondary popup)
HMENU hParentMenu;
if(AfxGetThreadState()->m_hTrackingMenu == m_hMenu)
{
state.m_pParentMenu=this; // parent == child for tracking popup
}
else if((hParentMenu=::GetMenu(pWnd->m_hWnd)) != NULL)
{
CWnd* pParent=pWnd->GetTopLevelParent();
// child windows don't have menus -- need to go to the top!
if(pParent != NULL &&
(hParentMenu=::GetMenu(pParent->m_hWnd)) != NULL)
{
int nIndexMax=::GetMenuItemCount(hParentMenu);
for (int nIndex=0; nIndex < nIndexMax; nIndex++)
{
if(::GetSubMenu(hParentMenu, nIndex) == m_hMenu)
{
// when popup is found, m_pParentMenu is containing menu
state.m_pParentMenu=CMenu::FromHandle(hParentMenu);
break;
}
}
}
}
state.m_nIndexMax=GetMenuItemCount();
for (state.m_nIndex=0; state.m_nIndex < state.m_nIndexMax; state.m_nIndex++)
{
state.m_nID=GetMenuItemID(state.m_nIndex);
if(state.m_nID == 0)
continue; // menu separator or invalid cmd - ignore it
ASSERT(state.m_pOther == NULL);
ASSERT(state.m_pMenu != NULL);
if(state.m_nID == (UINT)-1)
{
// possibly a popup menu, route to first item of that popup
state.m_pSubMenu=GetSubMenu(state.m_nIndex);
if(state.m_pSubMenu == NULL ||
(state.m_nID=state.m_pSubMenu->GetMenuItemID(0)) == 0 ||
state.m_nID == (UINT)-1)
{
continue; // first item of popup can't be routed to
}
state.DoUpdate(pWnd, FALSE); // popups are never auto disabled
}
else
{
// normal menu item
// Auto enable/disable if frame window has 'm_bAutoMenuEnable'
// set and command is _not_ a system command.
state.m_pSubMenu=NULL;
state.DoUpdate(pWnd,
((CFrameWnd*)pWnd)->m_bAutoMenuEnable && state.m_nID<0xF000);
}
// adjust for menu deletions and additions
UINT nCount=GetMenuItemCount();
if(nCount < state.m_nIndexMax)
{
state.m_nIndex -= (state.m_nIndexMax - nCount);
while (state.m_nIndex < nCount &&
GetMenuItemID(state.m_nIndex) == state.m_nID)
{
state.m_nIndex++;
}
}
state.m_nIndexMax=nCount;
}
}
int COXBitmapMenu::SetCustomizedItem(int nIndex)
{
int nOldCustomizedItemIndex=m_nCustomizedItemIndex;
m_nCustomizedItemIndex=nIndex;
if(m_pPopupWnd!=NULL && ::IsWindow(m_pPopupWnd->GetSafeHwnd()))
{
if(nOldCustomizedItemIndex!=m_nCustomizedItemIndex)
{
if(nOldCustomizedItemIndex!=-1)
m_pPopupWnd->RedrawItem(nOldCustomizedItemIndex);
if(m_nCustomizedItemIndex!=-1)
m_pPopupWnd->RedrawItem(m_nCustomizedItemIndex);
}
SendCustomizeNotification(ID_OXCUSTBM_SET_CUSTOMIZE_ITEM);
}
return nOldCustomizedItemIndex;
}
BOOL COXBitmapMenu::DisplayCustomizeItemContextMenu(int nItemIndex, CPoint point)
{
ASSERT(nItemIndex>=0 && nItemIndex<(int)GetMenuItemCount());
COXBitmapMenuOrganizer* pOrganizer=
COXBitmapMenuOrganizer::FindOrganizer(AfxGetMainWnd()->GetSafeHwnd());
ASSERT(pOrganizer!=NULL);
CString sText;
MENUITEMINFO mii={ sizeof(MENUITEMINFO) };
mii.fMask=MIIM_TYPE|MIIM_DATA|MIIM_ID|MIIM_SUBMENU;
mii.cch=300;
mii.dwTypeData=sText.GetBuffer(mii.cch);
// ... zero-terminate string
mii.dwTypeData[0]=_T('\0');
VERIFY(::GetMenuItemInfo(GetSafeHmenu(),nItemIndex,TRUE,&mii));
sText.ReleaseBuffer();
COXItemInfo* pItemInfo=(COXItemInfo*)(mii.dwItemData);
ASSERT(AfxIsValidAddress(pItemInfo,sizeof(COXItemInfo)));
sText=pItemInfo->GetText();
// don't add most recent files used
if((int)mii.wID>=ID_FILE_MRU_FILE1 && (int)mii.wID<=ID_FILE_MRU_FILE16)
{
return FALSE;
}
// don't add MDIChild windows menu items
if((int)mii.wID>=AFX_IDM_FIRST_MDICHILD && mii.hSubMenu==NULL)
{
return FALSE;
}
CMenu menu;
if(!menu.CreatePopupMenu())
return FALSE;
// populate menu
CString sItem;
VERIFY(sItem.LoadString(IDS_OX_CUSTBM_DELETE));
VERIFY(menu.AppendMenu(MF_STRING,ID_OXCUSTBM_DELETE,sItem));
if((mii.fType&MFT_SEPARATOR)==0)
{
VERIFY(menu.AppendMenu(MF_SEPARATOR));
VERIFY(sItem.LoadString(IDS_OX_CUSTBM_APPEARANCE));
VERIFY(menu.AppendMenu(MF_STRING,ID_OXCUSTBM_APPEARANCE,
sItem));
VERIFY(menu.AppendMenu(MF_SEPARATOR));
if(pOrganizer->IsShowOnlyRecentlyUsedItems())
{
VERIFY(sItem.LoadString(IDS_OX_CUSTBM_RECENTLY_USED));
VERIFY(menu.AppendMenu(MF_STRING|
(pOrganizer->IsRecentlyUsed(this,nItemIndex) ? MF_CHECKED :
MF_UNCHECKED),ID_OXCUSTBM_RECENTLY_USED,sItem));
VERIFY(menu.AppendMenu(MF_SEPARATOR));
}
BOOL bSeparatorBefore=FALSE;
if(nItemIndex>0)
{
MENUITEMINFO mii={ sizeof(MENUITEMINFO) };
mii.fMask=MIIM_TYPE;
mii.cch=300;
mii.dwTypeData=sText.GetBuffer(mii.cch);
// ... zero-terminate string
mii.dwTypeData[0]=_T('\0');
VERIFY(::GetMenuItemInfo(GetSafeHmenu(),nItemIndex-1,TRUE,&mii));
sText.ReleaseBuffer();
bSeparatorBefore=((mii.fType&MFT_SEPARATOR)==0);
}
VERIFY(sItem.LoadString(IDS_OX_CUSTBM_SEPARATOR_BEFORE));
VERIFY(menu.AppendMenu(MF_STRING|(bSeparatorBefore ? 0 : MF_GRAYED),
ID_OXCUSTBM_SEPARATOR_BEFORE,sItem));
BOOL bSeparatorAfter=FALSE;
if(nItemIndex<(int)(GetMenuItemCount()-1))
{
MENUITEMINFO mii={ sizeof(MENUITEMINFO) };
mii.fMask=MIIM_TYPE;
mii.cch=300;
mii.dwTypeData=sText.GetBuffer(mii.cch);
// ... zero-terminate string
mii.dwTypeData[0]=_T('\0');
VERIFY(::GetMenuItemInfo(GetSafeHmenu(),nItemIndex+1,TRUE,&mii));
sText.ReleaseBuffer();
bSeparatorAfter=((mii.fType&MFT_SEPARATOR)==0);
}
VERIFY(sItem.LoadString(IDS_OX_CUSTBM_SEPARATOR_AFTER));
VERIFY(menu.AppendMenu(MF_STRING|(bSeparatorAfter ? 0 : MF_GRAYED),
ID_OXCUSTBM_SEPARATOR_AFTER,sItem));
}
CWnd* pWndOwner=NULL;
if(m_pPopupWnd!=NULL && ::IsWindow(m_pPopupWnd->GetSafeHwnd()))
pWndOwner=m_pPopupWnd;
menu.TrackPopupMenu(TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_RIGHTBUTTON,
point.x,point.y,pWndOwner);
return TRUE;
}
void COXBitmapMenu::OnCustBMDelete()
{
ASSERT(IsInCustomizationMode());
int nCustomizedItemIndex=GetCustomizedItem();
ASSERT(nCustomizedItemIndex!=-1);
if(SendCustomizeNotification(ID_OXCUSTBM_DELETE))
return;
VERIFY(DeleteMenu(nCustomizedItemIndex,MF_BYPOSITION));
m_nCustomizedItemIndex=-1;
UpdateContents();
}
void COXBitmapMenu::OnCustBMAppearance()
{
ASSERT(IsInCustomizationMode());
int nCustomizedItemIndex=GetCustomizedItem();
ASSERT(nCustomizedItemIndex!=-1);
UNUSED(nCustomizedItemIndex);
SendCustomizeNotification(ID_OXCUSTBM_APPEARANCE);
}
void COXBitmapMenu::OnCustBMSeparatorBefore()
{
ASSERT(IsInCustomizationMode());
int nCustomizedItemIndex=GetCustomizedItem();
ASSERT(nCustomizedItemIndex!=-1);
if(SendCustomizeNotification(ID_OXCUSTBM_SEPARATOR_BEFORE))
return;
VERIFY(InsertMenu(nCustomizedItemIndex,MF_SEPARATOR|MF_BYPOSITION));
UpdateContents();
SetCustomizedItem(nCustomizedItemIndex+1);
}
void COXBitmapMenu::OnCustBMSeparatorAfter()
{
ASSERT(IsInCustomizationMode());
int nCustomizedItemIndex=GetCustomizedItem();
ASSERT(nCustomizedItemIndex!=-1);
if(SendCustomizeNotification(ID_OXCUSTBM_SEPARATOR_AFTER))
return;
VERIFY(InsertMenu(nCustomizedItemIndex+1,MF_SEPARATOR|MF_BYPOSITION));
UpdateContents();
}
void COXBitmapMenu::OnCustBMRecentlyUsed()
{
ASSERT(IsInCustomizationMode());
int nCustomizedItemIndex=GetCustomizedItem();
ASSERT(nCustomizedItemIndex!=-1);
if(SendCustomizeNotification(ID_OXCUSTBM_RECENTLY_USED))
return;
COXBitmapMenuOrganizer* pOrganizer=
COXBitmapMenuOrganizer::FindOrganizer(AfxGetMainWnd()->GetSafeHwnd());
ASSERT(pOrganizer!=NULL);
if(pOrganizer->IsRecentlyUsed(this,nCustomizedItemIndex))
{
VERIFY(pOrganizer->
ExcludeFromRecentlyUsed(this,nCustomizedItemIndex));
}
else
{
VERIFY(pOrganizer->
AddToRecentlyUsed(this,nCustomizedItemIndex));
}
UpdateContents();
}
LRESULT COXBitmapMenu::SendCustomizeNotification(UINT nCustomizeCmdID)
{
ASSERT(GetPopupWnd()!=NULL);
HWND hWnd=m_hWndCustomizeOrganizer;
if(hWnd==NULL)
{
hWnd=AfxGetMainWnd()->GetSafeHwnd();
}
if(hWnd==NULL)
return (LRESULT)0;
NMBMCUSTOMIZE nmbmCustomize;
nmbmCustomize.nmhdr.code=OXBMN_CUSTOMIZECMD;
nmbmCustomize.nmhdr.hwndFrom=GetPopupWnd()->GetSafeHwnd();
nmbmCustomize.nmhdr.idFrom=::GetDlgCtrlID(hWnd);
nmbmCustomize.nCustomizeEventID=nCustomizeCmdID;
return ::SendMessage(hWnd,WM_NOTIFY,(WPARAM)nmbmCustomize.nmhdr.idFrom,
(LPARAM)&nmbmCustomize);
}
LONG COXBitmapMenu::OnDragEnter(WPARAM wParam, LPARAM lParam)
{
// toolbar must be in customizable state
if(!IsCustomizable())
return (LONG)FALSE;
// set flag that specifies that drag'n'drop operation is active
m_bDragDropOperation=TRUE;
return OnDragOver(wParam,lParam);
}
LONG COXBitmapMenu::OnDragOver(WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(wParam);
// toolbar must be in customizable state
if(!IsCustomizable())
return (LONG)FALSE;
// lParam is the pointer to SHBDROPTARGETACTION structure
LPSHBDROPTARGETACTION pSHBDTAction=(LPSHBDROPTARGETACTION)lParam;
ASSERT(pSHBDTAction!=NULL);
pSHBDTAction->result=(LRESULT)DROPEFFECT_NONE;
#ifdef OX_CUSTOMIZE_COMMANDS
// Can we use this object?
if(pSHBDTAction->pDataObject->
IsDataAvailable(COXDragDropCommands::m_cfCommandButton))
{
// analize the current cursor position
//
BOOL bBefore=TRUE;
int nItemIndex=HitTest(&pSHBDTAction->point,&bBefore);
int nInsertMarkIndex=(bBefore ? nItemIndex : nItemIndex+1);
SetInsertMark(nInsertMarkIndex);
// Check if the control key was pressed
if((pSHBDTAction->dwKeyState & MK_CONTROL)==MK_CONTROL)
pSHBDTAction->result=(LRESULT)DROPEFFECT_COPY;
else
pSHBDTAction->result=(LRESULT)DROPEFFECT_MOVE;
}
#endif // OX_CUSTOMIZE_COMMANDS
return (LONG)TRUE;
}
LONG COXBitmapMenu::OnDragLeave(WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(wParam);
if(!IsCustomizable())
return (LONG)FALSE;
// lParam is the pointer to SHBDROPTARGETACTION structure
LPSHBDROPTARGETACTION pSHBDTAction=(LPSHBDROPTARGETACTION)lParam;
ASSERT(pSHBDTAction!=NULL);
SetInsertMark(-1);
// reset flag that specifies that drag'n'drop operation is active
m_bDragDropOperation=FALSE;
return (LONG)TRUE;
}
LONG COXBitmapMenu::OnDrop(WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(wParam);
if(!IsCustomizable())
return (LONG)FALSE;
// lParam is the pointer to SHBDROPTARGETACTION structure
LPSHBDROPTARGETACTION pSHBDTAction=(LPSHBDROPTARGETACTION)lParam;
ASSERT(pSHBDTAction!=NULL);
pSHBDTAction->result=(LRESULT)FALSE;
#ifdef OX_CUSTOMIZE_COMMANDS
// if dragged item is to be copied or moved
if((pSHBDTAction->dropEffect&DROPEFFECT_COPY)!=0 ||
(pSHBDTAction->dropEffect&DROPEFFECT_MOVE)!=0)
{
// data must be in the specific format
ASSERT(pSHBDTAction->pDataObject->
IsDataAvailable(COXDragDropCommands::m_cfCommandButton));
int nItemIndex=GetInsertMark();
if(nItemIndex!=-1 || GetMenuItemCount()==0)
{
// Get the drag item info
//
HGLOBAL hgData=pSHBDTAction->pDataObject->
GetGlobalData(COXDragDropCommands::m_cfCommandButton);
ASSERT(hgData!=NULL);
// lock it
BYTE* lpItemData=(BYTE*)::GlobalLock(hgData);
if(!SendCustomizeNotification(ID_OXCUSTBM_INSERT_ITEM))
{
RetrieveDragDropMenuItem(lpItemData,GetSafeHmenu(),nItemIndex);
if(m_bDragDropOwner && m_nCustomizedItemIndex>=nItemIndex)
{
ASSERT(m_nCustomizedItemIndex!=-1);
m_nCustomizedItemIndex++;
ASSERT(GetDraggedItem()!=-1);
SetDraggedItem(GetDraggedItem()+1);
}
}
// unlock it
::GlobalUnlock(hgData);
// free it
::GlobalFree(hgData);
// remove insert mark
SetInsertMark(-1);
// drag'n'drop operation completed successfully
pSHBDTAction->result=(LRESULT)TRUE;
}
else
{
pSHBDTAction->result=(LRESULT)FALSE;
}
}
#endif // OX_CUSTOMIZE_COMMANDS
m_bDragDropOperation=FALSE;
// we handled the message
return (LONG)TRUE;
}
void COXBitmapMenu::RetrieveDragDropMenuItem(BYTE*& lpData, HMENU hMenu,
int nItemIndex)
{
ASSERT(lpData!=NULL);
ASSERT(hMenu!=NULL);
ASSERT(::IsMenu(hMenu));
COXBitmapMenuOrganizer* pOrganizer=
COXBitmapMenuOrganizer::FindOrganizer(AfxGetMainWnd()->GetSafeHwnd());
ASSERT(pOrganizer!=NULL);
while(TRUE)
{
// get button command ID
int nCommandID=*(int*)lpData;
lpData+=sizeof(int);
// get button text
CString sText((LPTSTR)lpData);
lpData+=sText.GetLength()+sizeof(TCHAR);
if(sText.IsEmpty() && nCommandID!=0)
{
HINSTANCE hInstance=
AfxFindResourceHandle(MAKEINTRESOURCE(nCommandID),RT_STRING);
ASSERT(hInstance!=NULL);
sText.LoadString(nCommandID);
int nPosition=sText.Find(_T('\n'));
if(nPosition!=-1)
sText=sText.Mid(nPosition+1);
}
ASSERT(!sText.IsEmpty() || nCommandID==0);
// get button image index
int nImageIndex=*(int*)lpData;
lpData+=sizeof(int);
UNREFERENCED_PARAMETER(nImageIndex);
// get button style
BYTE fsStyle=*(BYTE*)lpData;
lpData+=sizeof(BYTE);
UNREFERENCED_PARAMETER(fsStyle);
// get finish flag
int nFinish=*(int*)lpData;
lpData+=sizeof(int);
// update menu
if(nCommandID==-1)
{
HMENU hSubMenu=::CreatePopupMenu();
ASSERT(hSubMenu!=NULL);
pOrganizer->m_arrCreatedPopupMenus.Add(hSubMenu);
VERIFY(::InsertMenu(hMenu,nItemIndex,
MF_BYPOSITION|MF_POPUP|MF_STRING,(UINT_PTR)hSubMenu,sText)!=0);
/*
CMenu* pMenu=CMenu::FromHandle(hMenu);
ASSERT(pMenu!=NULL);
COXBitmapMenu* pBitmapMenu=DYNAMIC_DOWNCAST(COXBitmapMenu,pMenu);
if(pBitmapMenu!=NULL)
{
pOrganizer->ConvertBitmapMenu(pBitmapMenu,FALSE);
}
*/
if(nFinish!=0)
{
RetrieveDragDropMenuItem(lpData,hSubMenu,0);
}
}
else
{
VERIFY(::InsertMenu(hMenu,nItemIndex,
MF_BYPOSITION|(nCommandID==0 ? MF_SEPARATOR : MF_STRING),
(UINT)nCommandID,sText)!=0);
}
nItemIndex++;
if(nFinish==0 || nFinish==2)
break;
}
CMenu* pMenu=CMenu::FromHandle(hMenu);
ASSERT(pMenu!=NULL);
COXBitmapMenu* pBitmapMenu=DYNAMIC_DOWNCAST(COXBitmapMenu,pMenu);
if(pBitmapMenu==NULL)
{
pOrganizer->OnInitMenuPopup(pMenu,0,FALSE);
pMenu=CMenu::FromHandle(hMenu);
pBitmapMenu=DYNAMIC_DOWNCAST(COXBitmapMenu,pMenu);
}
ASSERT(pBitmapMenu!=NULL);
pBitmapMenu->UpdateContents();
}
int COXBitmapMenu::SetInsertMark(int nItemIndex)
{
ASSERT(nItemIndex>=-1 && nItemIndex<=(int)GetMenuItemCount());
int nOldInsertMark=m_nInsertMarkIndex;
m_nInsertMarkIndex=nItemIndex;
if(nOldInsertMark!=m_nInsertMarkIndex)
{
if(m_pPopupWnd!=NULL && ::IsWindow(m_pPopupWnd->GetSafeHwnd()))
{
if(nOldInsertMark!=-1)
{
int nInsertMark=nOldInsertMark;
if(nInsertMark==(int)GetMenuItemCount())
{
nInsertMark--;
}
m_pPopupWnd->RedrawItem(nInsertMark);
if(nOldInsertMark!=0 && nOldInsertMark!=(int)GetMenuItemCount() &&
nOldInsertMark!=m_nInsertMarkIndex+1)
{
m_pPopupWnd->RedrawItem(nOldInsertMark-1);
}
}
if(m_nInsertMarkIndex!=-1)
{
int nInsertMark=m_nInsertMarkIndex;
if(nInsertMark==(int)GetMenuItemCount())
nInsertMark--;
m_pPopupWnd->RedrawItem(nInsertMark);
if(m_nInsertMarkIndex!=0 &&
m_nInsertMarkIndex!=(int)GetMenuItemCount() &&
m_nInsertMarkIndex!=nOldInsertMark+1)
{
m_pPopupWnd->RedrawItem(m_nInsertMarkIndex-1);
}
}
}
SendCustomizeNotification(ID_OXCUSTBM_SET_INSERT_MARK);
}
return nOldInsertMark;
}
int COXBitmapMenu::HitTest(LPPOINT ppt, BOOL* pbBefore/*=NULL*/)
{
int nItemIndex=-1;
int nHeight=0;
for(int nIndex=0; nIndex<(int)GetMenuItemCount(); nIndex++)
{
MENUITEMINFO mii={ sizeof(mii) };
mii.fMask=MIIM_DATA;
VERIFY(::GetMenuItemInfo(GetSafeHmenu(),nIndex,TRUE,&mii));
MEASUREITEMSTRUCT mis;
mis.CtlType=ODT_MENU;
mis.itemData=mii.dwItemData;
mis.itemID=GetMenuItemID(nIndex);
mis.itemHeight=(UINT)-1;
mis.itemWidth=(UINT)-1;
MeasureItem(&mis);
nHeight+=mis.itemHeight;
if(ppt->y<=nHeight)
{
nItemIndex=nIndex;
if(pbBefore!=NULL)
*pbBefore=(ppt->y<=nHeight-(int)mis.itemHeight/2);
break;
}
}
return nItemIndex;
}
void COXBitmapMenu::UpdateContents()
{
COXBitmapMenuOrganizer* pOrganizer=
COXBitmapMenuOrganizer::FindOrganizer(AfxGetMainWnd()->GetSafeHwnd());
if(pOrganizer!=NULL)
{
pOrganizer->ConvertBitmapMenu(this,FALSE);
}
if(m_pPopupWnd!=NULL && ::IsWindow(m_pPopupWnd->GetSafeHwnd()))
{
m_pPopupWnd->OnMenuChanged();
}
}
void COXBitmapMenu::OnBeginDragDrop(int nIndex)
{
ASSERT(nIndex>=0 && nIndex<(int)GetMenuItemCount());
ASSERT(m_pPopupWnd!=NULL && ::IsWindow(m_pPopupWnd->GetSafeHwnd()));
UNUSED(nIndex);
// mark the control as the one that launched drag'n'drop operation
m_bDragDropOwner=TRUE;
#ifdef OX_CUSTOMIZE_COMMANDS
CString sText;
MENUITEMINFO mii={ sizeof(mii) };
mii.fMask=MIIM_DATA|MIIM_TYPE|MIIM_ID|MIIM_SUBMENU;
mii.cch=300;
mii.dwTypeData=sText.GetBuffer(mii.cch);
VERIFY(::GetMenuItemInfo(GetSafeHmenu(),nIndex,TRUE,&mii));
sText.ReleaseBuffer();
// don't allow to drag most recent files used
if((int)mii.wID>=ID_FILE_MRU_FILE1 && (int)mii.wID<=ID_FILE_MRU_FILE16)
{
// unmark as the control which launched drag'n'drop operation
m_bDragDropOwner=FALSE;
return;
}
// don't allow to drag MDIChild windows menu items
if((int)mii.wID>=AFX_IDM_FIRST_MDICHILD && mii.hSubMenu==NULL)
{
// unmark as the control which launched drag'n'drop operation
m_bDragDropOwner=FALSE;
return;
}
COXItemInfo* pItemInfo=(COXItemInfo*)(mii.dwItemData);
ASSERT(AfxIsValidAddress(pItemInfo,sizeof(COXItemInfo)));
ASSERT(!pItemInfo->GetText().IsEmpty() || mii.fType&MFT_SEPARATOR);
CMenu* pSubmenu=GetSubMenu(nIndex);
if(pSubmenu!=NULL)
{
COXBitmapMenu* pBMSubmenu=DYNAMIC_DOWNCAST(COXBitmapMenu,pSubmenu);
if(pBMSubmenu!=NULL)
{
if(pBMSubmenu->GetPopupWnd()!=NULL)
{
pBMSubmenu->GetPopupWnd()->ResetPopupMenu();
}
}
}
COleDataSource* pDataSource=
COXDragDropCommands::PrepareDragDropData(pItemInfo->GetText(),
pItemInfo->GetImageInfo()->GetIndex(),GetMenuItemID(nIndex),0,
GetSubMenu(nIndex)->GetSafeHmenu());
ASSERT(pDataSource!=NULL);
m_bDragDropOperation=TRUE;
SetDraggedItem(nIndex);
DROPEFFECT dropEffect=
COXDragDropCommands::DoDragDrop(pDataSource,GetDropSource(m_pPopupWnd));
if(DROPEFFECT_MOVE==dropEffect || (DROPEFFECT_NONE==dropEffect &&
::GetKeyState(VK_LBUTTON)>=0 && !m_bDragDropOperation))
{
if(!SendCustomizeNotification(ID_OXCUSTBM_DELETE_ITEM))
{
int nDraggedItemIndex=GetDraggedItem();
// delete item if it was moved
VERIFY(DeleteMenu(nDraggedItemIndex,MF_BYPOSITION));
m_nCustomizedItemIndex=-1;
UpdateContents();
}
}
SetDraggedItem(-1);
//delete drag source (we are responsible to do that)
delete pDataSource;
#endif // OX_CUSTOMIZE_COMMANDS
// unmark as the control which launched drag'n'drop operation
m_bDragDropOwner=FALSE;
}
COXMenuSkin* COXBitmapMenu::GetMenuSkin()
{
// Check if the app is derived from COXSkinnedApp
COXSkinnedApp* pSkinnedApp = DYNAMIC_DOWNCAST(COXSkinnedApp, AfxGetApp());
if (pSkinnedApp != NULL && pSkinnedApp->GetCurrentSkin() != NULL)
return pSkinnedApp->GetCurrentSkin()->GetMenuSkin();
else
{
// Create a classic skin for this class if not created already
if (m_pMenuSkin == NULL)
m_pMenuSkin = new COXMenuSkinClassic();
return m_pMenuSkin;
}
}
// Returns TRUE if the given item is a popup menu (has a submenu)
BOOL COXBitmapMenu::IsPopupItem(UINT nItemID)
{
if (nItemID == (UINT)-1)
return TRUE;
MENUITEMINFO mii;
::memset(&mii, 0, sizeof(MENUITEMINFO));
mii.cbSize = sizeof(MENUITEMINFO);
mii.fMask = MIIM_SUBMENU;
GetMenuItemInfo(nItemID, &mii);
if (mii.hSubMenu != NULL)
return TRUE;
else
return FALSE;
}
void COXBitmapMenu::RestoreMDI()
{
CMDIFrameWnd* pMainWnd = (CMDIFrameWnd*)AfxGetMainWnd();
CMDIChildWnd * active = pMainWnd->MDIGetActive();
active->MDIRestore();
pMainWnd->MDINext();
while(active != pMainWnd->MDIGetActive())
{
pMainWnd->MDIGetActive()->MDIRestore();
pMainWnd->MDINext();
}
}
void COXBitmapMenu::CloseMDI()
{
CMDIFrameWnd* pMainWnd = (CMDIFrameWnd*)AfxGetMainWnd();
CMDIChildWnd * active = pMainWnd->MDIGetActive();
if (active->GetActiveDocument()->IsModified())
{
CString sTitle;
active->GetActiveFrame()->GetWindowText(sTitle);
int ID = AfxMessageBox(_T("Save changes to ") + sTitle + _T(" ?"), MB_YESNOCANCEL);
switch(ID)
{
case IDCANCEL:
// Do nothing
break;
case IDYES:
active->GetActiveDocument()->DoFileSave();
// Fall through intended
case IDNO:
active->DestroyWindow();
}
}
else
{
active->DestroyWindow();
}
}
void COXBitmapMenu::MinimizeMDI()
{
CMDIFrameWnd* pMainWnd = (CMDIFrameWnd*)AfxGetMainWnd();
CMDIChildWnd * active = pMainWnd->MDIGetActive();
active->MDIRestore();
active->ShowWindow(SW_MINIMIZE);}
BOOL COXBitmapMenu::HandleMDICommandMessage(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
{
UNREFERENCED_PARAMETER(pHandlerInfo);
if (nCode == CN_UPDATE_COMMAND_UI)
{
switch(nID)
{
case ID_OXBITMAPMENU_CLOSE:
case ID_OXBITMAPMENU_MINIMIZE:
case ID_OXBITMAPMENU_RESTORE:
((CCmdUI *) pExtra)->Enable (TRUE);
return TRUE;
}
}
else
if (nCode == CN_COMMAND)
{
bool bHandled = false;
switch(nID)
{
case ID_OXBITMAPMENU_CLOSE:
CloseMDI();
bHandled = true;
break;
case ID_OXBITMAPMENU_MINIMIZE:
MinimizeMDI();
bHandled = true;
break;
case ID_OXBITMAPMENU_RESTORE:
RestoreMDI();
bHandled = true;
break;
case SC_MAXIMIZE:
return TRUE;
}
if(bHandled)
{
CMDIFrameWnd* pMainWnd = static_cast<CMDIFrameWnd*>(AfxGetMainWnd());
if(pMainWnd)
{
CMDIChildWnd* pActiveWnd = pMainWnd->MDIGetActive();
if(pActiveWnd)
{
pActiveWnd->GetSystemMenu(TRUE);
}
}
return TRUE;
}
}
return FALSE;
}
#ifndef CS_DROPSHADOW
#define CS_DROPSHADOW 0x00020000
#endif
BOOL COXBitmapMenu::RegisterWindowClass(HINSTANCE hInstance)
{
if (m_origWndProc != NULL)
return TRUE; // already registed
WNDCLASS wndclass;
if (GetClassInfo(hInstance,_T("#32768"),&wndclass))
m_origWndProc = wndclass.lpfnWndProc;
wndclass.lpfnWndProc = PopupWndProc;
wndclass.style &= ~CS_DROPSHADOW;
wndclass.style |= CS_SAVEBITS;
wndclass.hInstance = hInstance ;
RegisterClass(&wndclass);
if (GetClassInfo(hInstance,_T("#32768"),&wndclass))
return TRUE;
else
return FALSE;
}
LRESULT CALLBACK COXBitmapMenu::PopupWndProc(HWND hwnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
return GetMenuSkin()->MenuPopupWndProc(m_origWndProc, hwnd, nMsg, wParam, lParam);
}
void COXBitmapMenuPopupWnd::OnNcPaint()
{
COXBitmapMenu::GetMenuSkin()->OnNcPaintCustomizePopupWnd(this);
}
BOOL COXBitmapMenu::TrackPopupMenu(COXCoolToolBar* pCoolToolBar, CWnd* pWnd, LPCRECT lpRect)
{
// Determine the selected item
int iSelectedItem = -1;
CToolBarCtrl& ctrl = pCoolToolBar->GetToolBarCtrl();
int iButtonCount = ctrl.GetButtonCount();
for (int i = 0; i < iButtonCount; i++)
{
if (ctrl.IsButtonPressed(pCoolToolBar->GetItemID(i)))
{
iSelectedItem = i;
break;
}
}
if (iSelectedItem == -1)
iSelectedItem = ctrl.CommandToIndex(pCoolToolBar->m_iLastDropDownIndex);
// Determine the rectangle of the selected item
CRect rectItem;
pCoolToolBar->GetItemRect(iSelectedItem, &rectItem);
COXMenuBar* pMenuBar = DYNAMIC_DOWNCAST(COXMenuBar, pCoolToolBar);
if (pMenuBar != NULL && iSelectedItem == -1)
{
// This is the icon item
rectItem = pMenuBar->m_iconRect;
CRect rectWindow;
pMenuBar->GetWindowRect(rectWindow);
pMenuBar->ScreenToClient(&rectWindow);
CRect rectClient;
pMenuBar->GetClientRect(rectClient);
rectItem.left += rectWindow.left - rectClient.left;
rectItem.right += rectWindow.left - rectClient.left;
rectItem.top += rectWindow.top - rectClient.top;
rectItem.bottom += rectWindow.top - rectClient.top;
rectItem.InflateRect(3, 3);
}
pCoolToolBar->ClientToScreen(&rectItem);
// Determine the position of the popup menu relative to the selected item
CPoint ptTopLeft;
UINT nFlags, nPosFlags;
DeterminePosition(this, rectItem, pCoolToolBar->m_dwStyle, ptTopLeft, nFlags, nPosFlags);
// Clear the queue of any pending messages
MSG msg;
while (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) != 0)
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
COXShadowedItemWnd* pSIW = new COXShadowedItemWnd(pCoolToolBar, iSelectedItem, nPosFlags);
CRect rect;
pCoolToolBar->GetItemRect(iSelectedItem, rect);
rect.DeflateRect(0, 1);
// Save the item rectangle in screen coordinates
m_rectDropDownItem = rect;
pCoolToolBar->ClientToScreen(m_rectDropDownItem);
// Create the transparent window which will be responsible for drawing the shadow
// The transparent window must be a child of the main window
rect.InflateRect(0, 0, 4, 4);
pCoolToolBar->ClientToScreen(rect);
pSIW->CreateEx(WS_EX_TRANSPARENT | WS_EX_TOOLWINDOW, NULL, NULL, WS_CHILD | WS_VISIBLE,
rect, CWnd::GetDesktopWindow(), 0, NULL);
BOOL bResult = CMenu::TrackPopupMenu(nFlags, ptTopLeft.x, ptTopLeft.y, pWnd, lpRect);
pSIW->DestroyWindow();
delete pSIW;
pSIW = NULL;
m_rectDropDownItem.SetRectEmpty();
return bResult;
}
// Returns the size of the popup menu before it is displayed
CSize COXBitmapMenu::GetPopupMenuSize(CMenu* pMenu)
{
CSize szMenu(0, 0);
int iCount = pMenu->GetMenuItemCount();
for (int i = 0; i < iCount; i++)
{
UINT nItemID = pMenu->GetMenuItemID(i);
// Get the data member
MENUITEMINFO miinfo;
::memset(&miinfo, 0, sizeof(MENUITEMINFO));
miinfo.cbSize = sizeof(MENUITEMINFO);
miinfo.fMask = MIIM_DATA;
pMenu->GetMenuItemInfo(nItemID, &miinfo);
// Call CMenu::MeasureItem() to determine the item's dimensions
MEASUREITEMSTRUCT mi;
::memset(&mi, 0, sizeof(MEASUREITEMSTRUCT));
mi.CtlType = ODT_MENU;
mi.itemID = nItemID;
mi.itemData = miinfo.dwItemData;
pMenu->MeasureItem(&mi);
if (mi.itemHeight == 0 && DYNAMIC_DOWNCAST(COXBitmapMenu, pMenu) == NULL)
{
// This is not a COXBitmapMenu
if (nItemID == 0)
mi.itemHeight = 8; // separator
else
mi.itemHeight = 17; // normal item
}
if ((int) mi.itemWidth > szMenu.cx)
szMenu.cx = mi.itemWidth;
szMenu.cy += mi.itemHeight;
}
// Compensate for the non-client area
szMenu.cx += 18;
szMenu.cy += 6;
return szMenu;
}
// v9.3 update 01 fixes and changes: Manfred Drasch
// Horizontal menu:
// * wrong ypos under some circumstances
// * avoid a drawingproblem (the menubutton was painted over the popupmenu)
// Vertical menu:
// * wrong xpos under some circumstances
// Both:
// * Menu now shown over vertical Appbar/Sidebar, too
void COXBitmapMenu::DeterminePosition(CMenu* pMenu, LPCRECT lpItemRect, DWORD dwStyle, CPoint& ptTopLeft, UINT& nFlags, UINT& nPosFlags)
{
// Get the rectangle of the monitor ( + WorkArea) closest to the menu rectangle
CRect rctMonitorWorkArea;
CRect rctMonitor;
CPoint ptCursor;
HMONITOR hMonitor = ::MonitorFromRect(lpItemRect, MONITOR_DEFAULTTONEAREST);
MONITORINFO mi;
mi.cbSize = sizeof(MONITORINFO);
if(hMonitor!=NULL && ::GetMonitorInfo(hMonitor, &mi))
{
rctMonitorWorkArea = mi.rcWork;
rctMonitor = mi.rcMonitor;
}
else
{
rctMonitorWorkArea.SetRect(0,0,GetSystemMetrics(SM_CXSCREEN),GetSystemMetrics(SM_CYSCREEN));
rctMonitor.SetRect(0,0,GetSystemMetrics(SM_CXSCREEN),GetSystemMetrics(SM_CYSCREEN));
}
CSize sizeMenu = GetPopupMenuSize(pMenu);
ptTopLeft.x = 0;
ptTopLeft.y = 0;
nFlags = 0;
if (dwStyle & CBRS_ORIENT_HORZ)
{
// Horizontal menu
ptTopLeft.x = lpItemRect->left;
if (ptTopLeft.x < rctMonitor.left)
ptTopLeft.x = rctMonitor.left;
if (ptTopLeft.x + sizeMenu.cx > rctMonitor.right)
ptTopLeft.x = rctMonitor.right - 1;
else
{
if (ptTopLeft.x + sizeMenu.cx + 1 >= rctMonitorWorkArea.right)
{
ptTopLeft.x += sizeMenu.cx;
if (ptTopLeft.x == 0)
ptTopLeft.x = -1;
}
}
if (lpItemRect->bottom + sizeMenu.cy > rctMonitorWorkArea.bottom)
{
// The popup menu should be above the item
nFlags |= TPM_BOTTOMALIGN;
nPosFlags = OX_TPM_TOP;
ptTopLeft.y = lpItemRect->top + 1;
}
else
{
// The popup menu should be below the item
nFlags |= TPM_TOPALIGN;
nPosFlags = OX_TPM_BOTTOM;
ptTopLeft.y = lpItemRect->bottom - 1;
}
}
else
{
// Vertical menu
if (lpItemRect->right + sizeMenu.cx > rctMonitor.right)
{
// The popup menu should be left of the item
nFlags |= TPM_RIGHTALIGN;
nPosFlags = OX_TPM_LEFT;
ptTopLeft.x = lpItemRect->left;
}
else
{
// The popup menu should be right of the item
nFlags |= TPM_LEFTALIGN;
nPosFlags = OX_TPM_RIGHT;
if (lpItemRect->right + sizeMenu.cx + 1 >= rctMonitorWorkArea.right)
ptTopLeft.x = lpItemRect->right + sizeMenu.cx;
else
ptTopLeft.x = lpItemRect->right;
if (ptTopLeft.x == 0)
ptTopLeft.x = -1;
}
ptTopLeft.y = lpItemRect->top + 1;
if (ptTopLeft.y < rctMonitorWorkArea.top)
ptTopLeft.y = rctMonitorWorkArea.top;
if (ptTopLeft.y + sizeMenu.cy > rctMonitorWorkArea.bottom)
ptTopLeft.y = rctMonitorWorkArea.bottom - sizeMenu.cy;
}
}