You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Galaxy/src/Screenshot/PopUpMenu.cpp

1466 lines
49 KiB

/*
Copyright (C) 2004 Jacquelin POTIER <jacquelin.potier@free.fr>
Dynamic aspect ratio code Copyright (C) 2004 Jacquelin POTIER <jacquelin.potier@free.fr>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
//-----------------------------------------------------------------------------
// Object: class helper for popupmenu control
//-----------------------------------------------------------------------------
#include "stdafx.h"
#include "popupmenu.h"
#define CPopUpMenu_ICON_SIZE_INCREMENT 2 // icon size increment used for shadow
#define CPopUpMenu_ICON_SHADOW_POSITION_DELTA 2
#define CPopUpMenu_TRANSPARENCY_INCREASE 130
//-----------------------------------------------------------------------------
// Name: CPopUpMenu
// Object: Constructor.
// Parameters :
// in :
// out :
// return :
//-----------------------------------------------------------------------------
CPopUpMenu::CPopUpMenu()
{
this->CommonConstructor();
this->ParentPopUpMenu=NULL;
}
CPopUpMenu::CPopUpMenu(CPopUpMenu* ParentPopUpMenu)
{
this->CommonConstructor();
this->ParentPopUpMenu=ParentPopUpMenu;
}
//#include <Uxtheme.h>
//#pragma comment (lib,"uxtheme.lib")
void CPopUpMenu::CommonConstructor()
{
this->bThemingEnabledForVistaOrNewer = FALSE;
if ( ((LOBYTE(LOWORD(::GetVersion())))>=6) ) // if vista or newer os
{
// dynamic loading to avoid static linking
HMODULE hmod = ::GetModuleHandle(_T("uxtheme.dll"));
if (!hmod)
hmod = ::LoadLibrary(_T("uxtheme.dll"));
if( hmod )
{
FARPROC pfIsThemeActive = ::GetProcAddress(hmod,"IsThemeActive");
this->bThemingEnabledForVistaOrNewer = pfIsThemeActive();
}
}
this->bAllowIconsEffects=TRUE;
this->MenuSelectCallback=NULL;
this->MenuSelectUserParam=NULL;
this->MouseRightButtonUpCallback=NULL;
this->MouseRightButtonUpUserParam=NULL;
this->hPopUpMenu=::CreatePopupMenu();
this->CurrentMenuId=0;
MENUINFO mnfo;
mnfo.cbSize = sizeof(mnfo);
mnfo.fMask = MIM_STYLE | MIM_MENUDATA;
mnfo.dwStyle = MNS_CHECKORBMP; //| MNS_AUTODISMISS can make menu to disappear when used on toolbar
mnfo.dwMenuData = (ULONG_PTR)this;
::SetMenuInfo(this->hPopUpMenu, &mnfo);
}
//-----------------------------------------------------------------------------
// Name: ~CPopUpMenu
// Object: Destructor. SUBMENU OBJECT ARE NOT DELETED
// Parameters :
// in :
// out :
// return :
//-----------------------------------------------------------------------------
CPopUpMenu::~CPopUpMenu()
{
std::vector<HBITMAP>::iterator Iterator;
for (Iterator = this->ListLoadedBitmapToFree.begin(); Iterator!=this->ListLoadedBitmapToFree.end(); Iterator++)
{
::DeleteObject(*Iterator);
}
::DestroyMenu(this->hPopUpMenu);
}
//-----------------------------------------------------------------------------
// Name: GetControlHandle
// Object: return the handle to the control
// Parameters :
// in :
// out :
// return : HWND handle to the control
//-----------------------------------------------------------------------------
HMENU CPopUpMenu::GetControlHandle()
{
return this->hPopUpMenu;
}
//-----------------------------------------------------------------------------
// Name: GetParentPopUpMenu
// Object: return pointer to the parent menu or NULL if no parent menu
// Parameters :
// in :
// out :
// return : pointer to the parent menu or NULL if no parent menu
//-----------------------------------------------------------------------------
CPopUpMenu* CPopUpMenu::GetParentPopUpMenu()
{
return this->ParentPopUpMenu;
}
//-----------------------------------------------------------------------------
// Name: GetNextMenuId
// Object: get next unique menu Id for all Menu and SubMenu
// Parameters :
// in :
// out :
// return : next unique menu Id for all Menu and SubMenu
//-----------------------------------------------------------------------------
UINT CPopUpMenu::GetNextMenuId()
{
if (this->ParentPopUpMenu)
return this->ParentPopUpMenu->GetNextMenuId();
else
{
// this assume we'll never return a 0 menuId
// (as 0 is returned by TrackPopupMenuEx if no item is selected)
this->CurrentMenuId++;
return this->CurrentMenuId;
}
}
//-----------------------------------------------------------------------------
// Name: GetNextMenuId
// Object: get max used unique menu Id for all Menu and SubMenu
// Parameters :
// in :
// out :
// return : max used unique menu Id for all Menu and SubMenu
//-----------------------------------------------------------------------------
UINT CPopUpMenu::GetMaxMenuId()
{
if (this->ParentPopUpMenu)
return this->ParentPopUpMenu->GetMaxMenuId();
else
{
return this->CurrentMenuId;
}
}
//-----------------------------------------------------------------------------
// Name: GetSubMenu
// Object: get sub menu associated menu id
// Parameters :
// in : UINT MenuID : menu id
// out :
// return : CPopUpMenu object pointer on success, NULL if no sub menu associated (or on error)
//-----------------------------------------------------------------------------
CPopUpMenu* CPopUpMenu::GetSubMenu(UINT MenuID)
{
MENUITEMINFO mii={0};
mii.cbSize=sizeof(MENUITEMINFO);
mii.fMask=MIIM_SUBMENU | MIIM_DATA;
if (!::GetMenuItemInfo(this->hPopUpMenu,MenuID,FALSE,&mii))
return NULL;
if (!mii.hSubMenu)
return NULL;
MENUINFO mi={0};
mi.cbSize = sizeof(MENUINFO);
mi.fMask = MIM_MENUDATA;
if (!::GetMenuInfo(mii.hSubMenu,&mi))
return NULL;
return (CPopUpMenu*)mi.dwMenuData;
}
//-----------------------------------------------------------------------------
// Name: SetIcon
// Object: set menu item icon (loads default icon size)
// Parameters :
// in : UINT MenuID : menu id
// int IdIcon : resource icon id
// HINSTANCE hInstance : module handle containing icon id
// out :
// return : TRUE on success
//-----------------------------------------------------------------------------
BOOL CPopUpMenu::SetIcon(UINT MenuID,int IdIcon,HINSTANCE hInstance)
{
return this->SetIcon(MenuID,IdIcon,hInstance,0,0);
}
//-----------------------------------------------------------------------------
// Name: SetIcon
// Object: set menu item icon
// Parameters :
// in : UINT MenuID : menu id
// int IdIcon : resource icon id
// int Width : icon width
// int Height : icon height
// HINSTANCE hInstance : module handle containing icon id
// out :
// return : TRUE on success
//-----------------------------------------------------------------------------
BOOL CPopUpMenu::SetIcon(UINT MenuID,int IdIcon,HINSTANCE hInstance,int Width,int Height)
{
return this->SetIcon(MenuID,(HICON)::LoadImage(hInstance, MAKEINTRESOURCE(IdIcon),IMAGE_ICON,Width,Height,LR_SHARED));
}
//-----------------------------------------------------------------------------
// Name: SetIcon
// Object: set menu item icon
// Parameters :
// in : UINT MenuID : menu id
// HICON hIcon : icon handle
// out :
// return : TRUE on success
//-----------------------------------------------------------------------------
BOOL CPopUpMenu::SetIcon(UINT MenuID,HICON hIcon)
{
MENUITEMINFO mii={0};
mii.cbSize=sizeof(MENUITEMINFO);
if (!hIcon)
return FALSE;
this->SetMenuItemBitmapInfo(&mii,hIcon);
return ::SetMenuItemInfo(this->hPopUpMenu,MenuID,FALSE,&mii);
}
//-----------------------------------------------------------------------------
// Name: Add
// Object:
// Parameters :
// in : TCHAR* Name : name of menu
// out :
// return : Id of item menu (used to remove it),0 if failed
//-----------------------------------------------------------------------------
UINT CPopUpMenu::Add(TCHAR* Name)
{
return this->Add(Name,NULL,this->GetItemCount());
}
//-----------------------------------------------------------------------------
// Name: Add
// Object:
// Parameters :
// in : TCHAR* Name : name of menu
// UINT Index : 0 based menu index
// out :
// return : Id of item menu (used to remove it),0 if failed
//-----------------------------------------------------------------------------
UINT CPopUpMenu::Add(TCHAR* Name,UINT Index)
{
return this->Add(Name,NULL,Index);
}
//-----------------------------------------------------------------------------
// Name: Add
// Object:
// Parameters :
// in : TCHAR* Name : name of menu
// HICON hIcon : icon handle
// out :
// return : Id of item menu (used to remove it),0 if failed
//-----------------------------------------------------------------------------
UINT CPopUpMenu::Add(TCHAR* Name,HICON hIcon)
{
return this->Add(Name,hIcon,this->GetItemCount());
}
//-----------------------------------------------------------------------------
// Name: Add
// Object:
// Parameters :
// in : TCHAR* Name : name of menu
// int IdIcon : icon id
// HINSTANCE hInstance : hinstance containing icon id
// out :
// return : Id of item menu (used to remove it),0 if failed
//-----------------------------------------------------------------------------
UINT CPopUpMenu::Add(TCHAR* Name,int IdIcon,HINSTANCE hInstance)
{
// load icon
HICON hIcon=(HICON)::LoadImage(hInstance, MAKEINTRESOURCE(IdIcon),IMAGE_ICON,0,0,LR_SHARED);
return this->Add(Name,hIcon,this->GetItemCount());
}
//-----------------------------------------------------------------------------
// Name: Add
// Object:
// Parameters :
// in : TCHAR* Name : name of menu
// int IdIcon : icon id
// HINSTANCE hInstance : hinstance containing icon id
// UINT Index : 0 based menu index
// out :
// return : Id of item menu (used to remove it),0 if failed
//-----------------------------------------------------------------------------
UINT CPopUpMenu::Add(TCHAR* Name,int IdIcon,HINSTANCE hInstance,UINT Index)
{
return this->Add(Name,IdIcon,hInstance,0,0,Index);
}
//-----------------------------------------------------------------------------
// Name: Add
// Object:
// Parameters :
// in : TCHAR* Name : name of menu
// int IdIcon : icon id
// HINSTANCE hInstance : hinstance containing icon id
// int Width : icon width
// int Height : icon height
// UINT Index : 0 based menu index
// out :
// return : Id of item menu (used to remove it),0 if failed
//-----------------------------------------------------------------------------
UINT CPopUpMenu::Add(TCHAR* Name,int IdIcon,HINSTANCE hInstance,int Width,int Height,UINT Index)
{
// load icon
HICON hIcon=(HICON)::LoadImage(hInstance, MAKEINTRESOURCE(IdIcon),IMAGE_ICON,Width,Height,LR_SHARED);
return this->Add(Name,hIcon,Index);
}
//-----------------------------------------------------------------------------
// Name: Add
// Object:
// Parameters :
// in : TCHAR* Name : name of menu
// HICON hIcon : icon handle
// UINT Index : 0 based menu index
// out :
// return : Id of item menu (used to remove it),0 if failed
//-----------------------------------------------------------------------------
UINT CPopUpMenu::Add(TCHAR* Name,HICON hIcon,UINT Index)
{
UINT MenuId=this->GetNextMenuId();
MENUITEMINFO mii={0};
mii.cbSize=sizeof(MENUITEMINFO);
mii.fMask = MIIM_FTYPE|MIIM_STRING|MIIM_ID;
mii.fType = MFT_STRING;
mii.dwTypeData=Name;
mii.wID=MenuId;
this->SetMenuItemBitmapInfo(&mii,hIcon);
// insert menu
if (!::InsertMenuItem(this->hPopUpMenu,
Index,
TRUE,
&mii
)
)
return 0;
return MenuId;
}
//-----------------------------------------------------------------------------
// Name: ReplaceMenuId
// Object: change menu id.
// WARNING NO CHECK IS DONE IF NEW ID IS ALREADY EXISTING : if it's the case
// you will run into trouble for the multiple id access
//
// Parameters :
// in : UINT OldMenuID : old menu id
// UINT NewMenuID : new menu id
// out :
// return : TRUE on success
//-----------------------------------------------------------------------------
BOOL CPopUpMenu::ReplaceMenuId(UINT OldMenuID,UINT NewMenuID)
{
MENUITEMINFO mii={0};
mii.cbSize=sizeof(MENUITEMINFO);
mii.fMask=MIIM_ID;
mii.wID=NewMenuID;
return ::SetMenuItemInfo(this->hPopUpMenu,OldMenuID,FALSE,&mii);
}
//-----------------------------------------------------------------------------
// Name: SetCheckedState
// Object:
// Parameters :
// in : UINT MenuID : menu id
// BOOL bChecked : new checked state
// out :
// return :
//-----------------------------------------------------------------------------
void CPopUpMenu::SetCheckedState(UINT MenuID,BOOL bChecked)
{
UINT uCheck;
if(bChecked)
uCheck=MF_CHECKED;
else
uCheck=MF_UNCHECKED;
::CheckMenuItem(this->hPopUpMenu,MenuID,MF_BYCOMMAND|uCheck);
}
//-----------------------------------------------------------------------------
// Name: IsChecked
// Object:
// Parameters :
// in : UINT MenuID : menu id
// out :
// return : TRUE if menu item is checked
//-----------------------------------------------------------------------------
BOOL CPopUpMenu::IsChecked(UINT MenuID)
{
if (MF_CHECKED & ::GetMenuState(this->hPopUpMenu,MenuID,MF_BYCOMMAND))
return TRUE;
else
return FALSE;
}
//-----------------------------------------------------------------------------
// Name: SetEnabledState
// Object:
// Parameters :
// in : UINT MenuID : menu id
// BOOL bEnabled : new enabled state
// out :
// return :
//-----------------------------------------------------------------------------
void CPopUpMenu::SetEnabledState(UINT MenuID,BOOL bEnabled)
{
UINT uEnable;
if(bEnabled)
uEnable=MF_ENABLED;
else
uEnable=MF_GRAYED;
::EnableMenuItem(this->hPopUpMenu,MenuID,MF_BYCOMMAND|uEnable);
}
//-----------------------------------------------------------------------------
// Name: IsEnabled
// Object:
// Parameters :
// in : UINT MenuID : menu id
// out :
// return :
//-----------------------------------------------------------------------------
BOOL CPopUpMenu::IsEnabled(UINT MenuID)
{
UINT uEnable=::GetMenuState(this->hPopUpMenu,MenuID,MF_BYCOMMAND);
if (uEnable==(UINT)-1)
return FALSE;
return !(uEnable & (MF_DISABLED|MF_GRAYED));
}
//-----------------------------------------------------------------------------
// Name: Remove
// Object:
// Parameters :
// in : UINT MenuID
// out :
// return :
//-----------------------------------------------------------------------------
void CPopUpMenu::Remove(UINT MenuID)
{
::RemoveMenu(this->hPopUpMenu,MenuID,MF_BYCOMMAND);
}
//-----------------------------------------------------------------------------
// Name: AddSeparator
// Object:
// Parameters :
// in :
// out :
// return : Id of item menu (used to remove it),0 if failed
//-----------------------------------------------------------------------------
UINT CPopUpMenu::AddSeparator()
{
UINT MenuId=this->GetNextMenuId();
if(!::AppendMenu( this->hPopUpMenu,MF_SEPARATOR,MenuId,_T("")))
return 0;
return MenuId;
}
//-----------------------------------------------------------------------------
// Name: AddSeparator
// Object:
// Parameters :
// in : UINT Index : menu index
// out :
// return : Id of item menu (used to remove it),0 if failed
//-----------------------------------------------------------------------------
UINT CPopUpMenu::AddSeparator(UINT Index)
{
UINT MenuId=this->GetNextMenuId();
if (!::InsertMenu( this->hPopUpMenu,Index, MF_SEPARATOR|MF_BYPOSITION,MenuId,_T("")))
return 0;
return MenuId;
}
//-----------------------------------------------------------------------------
// Name: AddSubMenu
// Object:
// Parameters :
// in : TCHAR* SubMenuName : Name of submenu
// CPopUpMenu* SubMenu : pointer to an initialized CPopUpMenu
// UINT Index : SubMenu 0 based index in the current menu
// out :
// return : Id of item menu (used to remove it),0 if failed
//-----------------------------------------------------------------------------
UINT CPopUpMenu::AddSubMenu(TCHAR* SubMenuName,CPopUpMenu* SubMenu)
{
return this->AddSubMenu(SubMenuName,SubMenu,(UINT)-1);
}
//-----------------------------------------------------------------------------
// Name: AddSubMenu
// Object:
// Parameters :
// in : TCHAR* SubMenuName : Name of submenu
// CPopUpMenu* SubMenu : pointer to an initialized CPopUpMenu
// UINT Index : SubMenu 0 based index in the current menu
// out :
// return : Id of item menu (used to remove it),0 if failed
//-----------------------------------------------------------------------------
UINT CPopUpMenu::AddSubMenu(TCHAR* SubMenuName,CPopUpMenu* SubMenu,UINT Index)
{
return this->AddSubMenu(SubMenuName,SubMenu,0,Index);
}
//-----------------------------------------------------------------------------
// Name: AddSubMenu
// Object: add submenu with icon
// Parameters :
// in : TCHAR* SubMenuName : Name of submenu
// CPopUpMenu* SubMenu : pointer to an initialized CPopUpMenu
// int IdIcon : icon id
// HINSTANCE hInstance : instance containing icon id
// UINT Index : SubMenu 0 based index in the current menu
// out :
// return : Id of item menu (used to remove it),0 if failed
//-----------------------------------------------------------------------------
UINT CPopUpMenu::AddSubMenu(TCHAR* SubMenuName,CPopUpMenu* SubMenu,int IdIcon,HINSTANCE hInstance)
{
return this->AddSubMenu(SubMenuName,SubMenu,IdIcon,hInstance,(UINT)-1);
}
//-----------------------------------------------------------------------------
// Name: AddSubMenu
// Object: add submenu with icon
// Parameters :
// in : TCHAR* SubMenuName : Name of submenu
// CPopUpMenu* SubMenu : pointer to an initialized CPopUpMenu
// int IdIcon : icon id
// HINSTANCE hInstance : instance containing icon id
// UINT Index : SubMenu 0 based index in the current menu
// out :
// return : Id of item menu (used to remove it),0 if failed
//-----------------------------------------------------------------------------
UINT CPopUpMenu::AddSubMenu(TCHAR* SubMenuName,CPopUpMenu* SubMenu,int IdIcon,HINSTANCE hInstance,UINT Index)
{
HICON hIcon=(HICON)::LoadImage(hInstance, MAKEINTRESOURCE(IdIcon),IMAGE_ICON,0,0,LR_SHARED);
return this->AddSubMenu(SubMenuName,SubMenu,hIcon,Index);
}
//-----------------------------------------------------------------------------
// Name: AddSubMenu
// Object: add submenu with icon
// Parameters :
// in : TCHAR* SubMenuName : Name of submenu
// CPopUpMenu* SubMenu : pointer to an initialized CPopUpMenu
// HICON hIcon : submenu icon handle
// out :
// return : Id of item menu (used to remove it),0 if failed
//-----------------------------------------------------------------------------
UINT CPopUpMenu::AddSubMenu(TCHAR* SubMenuName,CPopUpMenu* SubMenu,HICON hIcon)
{
return this->AddSubMenu(SubMenuName,SubMenu,hIcon,(UINT)-1);
}
//-----------------------------------------------------------------------------
// Name: AddSubMenu
// Object: add submenu with icon
// Parameters :
// in : TCHAR* SubMenuName : Name of submenu
// CPopUpMenu* SubMenu : pointer to an initialized CPopUpMenu
// HICON hIcon : submenu icon handle
// UINT Index : SubMenu 0 based index in the current menu
// out :
// return : Id of item menu (used to remove it),0 if failed
//-----------------------------------------------------------------------------
UINT CPopUpMenu::AddSubMenu(TCHAR* SubMenuName,CPopUpMenu* SubMenu,HICON hIcon,UINT Index)
{
MENUITEMINFO MenuItem={0};
UINT MenuId=this->GetNextMenuId();
MenuItem.cbSize=sizeof(MENUITEMINFO);
MenuItem.fMask=MIIM_SUBMENU|MIIM_STRING|MIIM_ID;
MenuItem.hSubMenu=SubMenu->GetControlHandle();
MenuItem.fType=MFT_STRING;
MenuItem.cch=(UINT)_tcslen(SubMenuName);
MenuItem.dwTypeData=SubMenuName;
MenuItem.wID=MenuId;
this->SetMenuItemBitmapInfo(&MenuItem,hIcon);
if(!::InsertMenuItem(this->hPopUpMenu,Index,TRUE,&MenuItem))
return 0;
return MenuId;
}
void CPopUpMenu::SetMenuItemBitmapInfo(MENUITEMINFO* pMenuItem,HICON hIcon)
{
if (hIcon)
{
// on vista or newer os, if theming is enabled selected icon is not color-inverted,
// so there's no need to draw icon by ourselves, let system do it
if (this->bThemingEnabledForVistaOrNewer)
{
SIZE IconSize;
ICONINFO IconInfo;
if (::GetIconInfo(hIcon,&IconInfo))
{
IconSize.cx = IconInfo.xHotspot*2;
IconSize.cy = IconInfo.yHotspot*2;
// free icon infos
::DeleteObject(IconInfo.hbmColor);
::DeleteObject(IconInfo.hbmMask);
}
else
{
IconSize.cx = ::GetSystemMetrics(SM_CXICON);
IconSize.cy = ::GetSystemMetrics(SM_CYICON);
}
BITMAPV5HEADER bi;
void *lpBits;
ZeroMemory(&bi,sizeof(BITMAPV5HEADER));
bi.bV5Size = sizeof(BITMAPV5HEADER);
bi.bV5Width = IconSize.cx;
bi.bV5Height = IconSize.cy;
bi.bV5Planes = 1;
bi.bV5BitCount = 32;
bi.bV5Compression = BI_BITFIELDS;
// The following mask specification specifies a supported 32 BPP
// alpha format for Windows XP.
bi.bV5RedMask = 0x00FF0000;
bi.bV5GreenMask = 0x0000FF00;
bi.bV5BlueMask = 0x000000FF;
bi.bV5AlphaMask = 0xFF000000;
HDC hdcScreen = ::GetDC(NULL);
HDC hMemDC = ::CreateCompatibleDC(hdcScreen);
HBITMAP hBitmap = ::CreateDIBSection(hdcScreen, (BITMAPINFO *)&bi, DIB_RGB_COLORS, (void **)&lpBits, NULL, (DWORD)0);
// HBITMAP hBitmap = ::CreateCompatibleBitmap(hMemDC, IconSize.cx, IconSize.cy);
HBITMAP hOldBitmap = (HBITMAP)::SelectObject(hMemDC, hBitmap);
HBRUSH hBackgroundBrush = ::CreateSolidBrush(::GetSysColor(COLOR_MENU));
//::DrawIcon(hMemDC, 0, 0, hIcon);
::DrawIconEx(hMemDC,0,0,hIcon,IconSize.cx,IconSize.cy,0,
/*0*/ hBackgroundBrush, /* some icons needs a background color*/
DI_NORMAL /*| DI_NOMIRROR*/ );
::SelectObject(hMemDC, hOldBitmap);
::DeleteObject(hBackgroundBrush);
::DeleteDC(hMemDC);
::ReleaseDC(NULL,hdcScreen);
pMenuItem->fMask|=MIIM_BITMAP;
pMenuItem->hbmpItem = hBitmap;
ListLoadedBitmapToFree.push_back(hBitmap);
// to do : MenuItem.hbmpItem with must be deleted
}
else
{
// before vista icon of selected item in menu was inverted by default.
// to avoid this we have to manually draw icon by oursleves inside callback
// set item data for WM_MEASUREITEM and WM_DRAWITEM messages
pMenuItem->fMask|=MIIM_DATA;
pMenuItem->dwItemData=(ULONG_PTR)hIcon;
// set owner drawn for icon drawing
pMenuItem->fMask|=MIIM_BITMAP;
pMenuItem->hbmpItem = HBMMENU_CALLBACK;
//// for full owner drawn type use
//pMenuItem->fType|= MFT_OWNERDRAW;
}
}
}
//-----------------------------------------------------------------------------
// Name: GetItemCount
// Object:
// Parameters :
// in :
// out :
// return : number of item in the menu
//-----------------------------------------------------------------------------
int CPopUpMenu::GetItemCount()
{
return ::GetMenuItemCount(this->hPopUpMenu);
}
//-----------------------------------------------------------------------------
// Name: GetText
// Object:
// Parameters :
// in : UINT MenuID : menu ID
// int pszTextMaxSize : pszText max size in TCHAR. If 0, GetItemCount returns the
// number of required TCHAR
// out : TCHAR* pszText : Pointer to the buffer that receives the null-terminated string
// return : If the function succeeds, the return value specifies the number of characters copied to the buffer,
// not including the terminating null character
// If the function fails, the return value is zero
//-----------------------------------------------------------------------------
int CPopUpMenu::GetText(UINT MenuID,OUT TCHAR* pszText,IN int pszTextMaxSize)
{
return ::GetMenuString(this->hPopUpMenu,MenuID,pszText,pszTextMaxSize,MF_BYCOMMAND);
}
//-----------------------------------------------------------------------------
// Name: SetText
// Object:
// Parameters :
// in : UINT MenuID : menu ID
// TCHAR* pszText : Pointer to the input buffer
// out :
// return : TRUE on success, FALSE on error
//-----------------------------------------------------------------------------
BOOL CPopUpMenu::SetText(UINT MenuID,TCHAR* pszText)
{
MENUITEMINFO MenuItemInfo={0};
MenuItemInfo.cbSize=sizeof(MENUITEMINFO);
MenuItemInfo.fMask=MIIM_STRING;
MenuItemInfo.fType=MFT_STRING;
MenuItemInfo.cch=(UINT)_tcslen(pszText);
MenuItemInfo.dwTypeData=pszText;
return ::SetMenuItemInfo(this->hPopUpMenu,MenuID,FALSE,&MenuItemInfo);
}
//-----------------------------------------------------------------------------
// Name: GetID
// Object: retrieve menu ID from menu index
// Parameters :
// in : UINT Menu index : index
// out :
// return : -1 if not found, else menu id
//-----------------------------------------------------------------------------
int CPopUpMenu::GetID(UINT MenuIndex)
{
MENUITEMINFO MenuItemInfo={0};
MenuItemInfo.cbSize=sizeof(MENUITEMINFO);
MenuItemInfo.fMask=MIIM_ID;
if (!::GetMenuItemInfo(this->hPopUpMenu,MenuIndex,TRUE,&MenuItemInfo))
return -1;
return (int)MenuItemInfo.wID;
// return GetMenuItemID(this->hPopUpMenu,MenuIndex);
}
//-----------------------------------------------------------------------------
// Name: GetIndex
// Object: retrieve menu index from menu ID
// Parameters :
// in : UINT MenuId : menu id
// out :
// return : -1 if not found, else menu index
//-----------------------------------------------------------------------------
int CPopUpMenu::GetIndex(UINT MenuId)
{
int Cnt;
for (Cnt=0;Cnt<this->GetItemCount();Cnt++)
{
if ((UINT)this->GetID(Cnt)==MenuId)
{
return Cnt;
}
}
return -1;
}
//-----------------------------------------------------------------------------
// Name: Show
// Object:
// Parameters :
// in : int x : Horizontal location of the shortcut menu, in screen coordinates
// int y : Vertical location of the shortcut menu, in screen coordinates
// HWND hOwner : owner control handle
// out :
// return : 0 if no item selected, item id else
//-----------------------------------------------------------------------------
UINT CPopUpMenu::Show(int x,int y, HWND hOwner)
{
return this->Show(x,y,hOwner,FALSE);
}
//-----------------------------------------------------------------------------
// Name: Show
// Object:
// Parameters :
// in : int x : Horizontal location of the shortcut menu, in screen coordinates
// int y : Vertical location of the shortcut menu, in screen coordinates
// HWND hOwner : owner control handle
// BOOL PositionRelativeToOwner : TRUE if position is relative to owner
// FALSE for an absolute position
// out :
// return : 0 if no item selected, item id else
//-----------------------------------------------------------------------------
UINT CPopUpMenu::Show(int x,int y, HWND hOwner,BOOL PositionRelativeToOwner)
{
return this->Show(x,y,hOwner,PositionRelativeToOwner,FALSE);
}
//-----------------------------------------------------------------------------
// Name: Show
// Object:
// Parameters :
// in : int x : Horizontal location of the shortcut menu, in screen coordinates
// int y : Vertical location of the shortcut menu, in screen coordinates
// HWND hOwner : owner control handle
// BOOL PositionRelativeToOwner : TRUE if position is relative to owner
// FALSE for an absolute position
// BOOL ShowUpper : TRUE to show menu upper y point
// out :
// return : 0 if no item selected, item id else
//-----------------------------------------------------------------------------
UINT CPopUpMenu::Show(int x,int y, HWND hOwner,BOOL PositionRelativeToOwner,BOOL ShowUpper)
{
if (PositionRelativeToOwner)
{
RECT Rect;
::GetWindowRect(hOwner,&Rect);
x+=Rect.left;
y+=Rect.top;
}
// menu flag must be without TPM_RIGHTBUTTON flag to get WM_MENURBUTTONUP messages
UINT fuFlags=TPM_LEFTALIGN|TPM_RETURNCMD;
if (ShowUpper)
{
fuFlags|=TPM_BOTTOMALIGN;
}
else
{
fuFlags|=TPM_TOPALIGN;
}
UINT TrackPopupMenuRet;
HWND hWnd=hOwner;
// install a subclassing wndproc
UINT_PTR uIdSubclass=0;
DWORD_PTR dwRefData=(DWORD_PTR)this;
::SetWindowSubclass(hWnd,CPopUpMenu::SubClassWndProc,uIdSubclass,dwRefData);
::SetForegroundWindow(hWnd); // in case of use with notify icons
TrackPopupMenuRet=(UINT)::TrackPopupMenuEx(this->hPopUpMenu,fuFlags,x,y,hOwner,NULL);
if (TrackPopupMenuRet==0)
{
if (::GetLastError()==ERROR_POPUP_ALREADY_ACTIVE)
TrackPopupMenuRet=(UINT)::TrackPopupMenuEx(this->hPopUpMenu,fuFlags|TPM_RECURSE,x,y,hOwner,NULL);
}
// remove subclassing wndproc
::RemoveWindowSubclass(hWnd,CPopUpMenu::SubClassWndProc,uIdSubclass);
// MSDN :
//However, when the current window is the foreground window,
//the second time this menu is displayed, it displays and then immediately disappears.
//To correct this, you must force a task switch to the application that called
//TrackPopupMenu at some time in the near future.
//This is done by posting a benign message to the window or thread
::PostMessage(hWnd, WM_NULL, 0, 0);
return TrackPopupMenuRet;
}
//-----------------------------------------------------------------------------
// Name: OnMeasureItem
// Object: return needed pRect size to display picture (full item menu for MFT_OWNERDRAW)
// Parameters :
// in : HWND hwnd : hwnd
// inout : LPMEASUREITEMSTRUCT lpmis : pointer measured item struct
// out :
// return : TRUE if message has been proceed
//-----------------------------------------------------------------------------
BOOL CPopUpMenu::OnMeasureItem(HWND hwnd, LPMEASUREITEMSTRUCT lpmis)
{
UNREFERENCED_PARAMETER(hwnd);
// assume type is a menu
if (lpmis->CtlType!=ODT_MENU)
return FALSE;
// assume to have item associated data
if (!lpmis->itemData)
return FALSE;
// extract icon infos from item data
ICONINFO IconInfo;
if (!::GetIconInfo((HICON)lpmis->itemData, &IconInfo))
return FALSE;
// get bitmap from icon
BITMAP Bitmap;
::GetObject(IconInfo.hbmColor, sizeof(Bitmap), &Bitmap);
// free icon infos
::DeleteObject(IconInfo.hbmColor);
::DeleteObject(IconInfo.hbmMask);
// use bitmap size infos
lpmis->itemWidth = Bitmap.bmWidth;
lpmis->itemHeight = Bitmap.bmHeight;
if (this->bAllowIconsEffects)
{
lpmis->itemWidth+= CPopUpMenu_ICON_SIZE_INCREMENT;
lpmis->itemHeight+= CPopUpMenu_ICON_SIZE_INCREMENT;
}
return TRUE;
}
HICON CreateGrayscaleIcon(HICON hIcon)
{
HICON hGrayIcon = NULL;
HDC hdc = NULL, hMemDC1 = NULL, hMemDC2 = NULL;
HBITMAP hOldBmp1 = NULL, hOldBmp2 = NULL;
ICONINFO csII, csGrayII;
BOOL bRetValue = FALSE;
bRetValue = ::GetIconInfo(hIcon, &csII);
if (bRetValue == FALSE)
return NULL;
hdc = ::GetDC(NULL);
if (!hdc)
return NULL;
hMemDC1 = ::CreateCompatibleDC(hdc);
if (!hMemDC1)
{
::ReleaseDC(NULL, hdc);
return NULL;
}
hMemDC2 = ::CreateCompatibleDC(hdc);
if (!hMemDC2)
{
::DeleteDC(hMemDC1);
::ReleaseDC(NULL, hdc);
return NULL;
}
BITMAPV5HEADER bi;
DWORD Width;
DWORD Height;
void *lpBits;
Width = csII.xHotspot*2; // width of Icon
Height = csII.yHotspot*2; // height of Icon
ZeroMemory(&bi,sizeof(BITMAPV5HEADER));
bi.bV5Size = sizeof(BITMAPV5HEADER);
bi.bV5Width = Width;
bi.bV5Height = Height;
bi.bV5Planes = 1;
bi.bV5BitCount = 32;
bi.bV5Compression = BI_BITFIELDS;
// The following mask specification specifies a supported 32 BPP
// alpha format for Windows XP.
bi.bV5RedMask = 0x00FF0000;
bi.bV5GreenMask = 0x0000FF00;
bi.bV5BlueMask = 0x000000FF;
bi.bV5AlphaMask = 0xFF000000;
// Create the DIB section with an alpha channel.
csGrayII.hbmColor = ::CreateDIBSection(hdc, (BITMAPINFO *)&bi, DIB_RGB_COLORS, (void **)&lpBits, NULL, (DWORD)0);
if (csGrayII.hbmColor)
{
hOldBmp1 = (HBITMAP)::SelectObject(hMemDC1, csII.hbmColor);
hOldBmp2 = (HBITMAP)::SelectObject(hMemDC2, csGrayII.hbmColor);
::BitBlt(hMemDC2, 0, 0, Width, Height, hMemDC1, 0, 0, SRCCOPY);
DWORD dwLoopY = 0, dwLoopX = 0;
COLORREF crPixel = 0;
BYTE byNewPixel = 0;
DWORD *lpdwPixel;
lpdwPixel = (DWORD *)lpBits;
for (dwLoopY = 0; dwLoopY < Height; dwLoopY++)
{
for (dwLoopX = 0; dwLoopX < Width; dwLoopX++)
{
crPixel = (*lpdwPixel) & 0x00FFFFFF;
if (crPixel)
byNewPixel = (BYTE)((GetRValue(crPixel) * 0.299) + (GetGValue(crPixel) * 0.587) + (GetBValue(crPixel) * 0.114));
else
byNewPixel = 0;
// Clear the color bits
*lpdwPixel &= 0xFF000000;
// Set the new alpha bits
*lpdwPixel |= RGB(byNewPixel, byNewPixel, byNewPixel) ;
lpdwPixel++;
} // for
} // for
::SelectObject(hMemDC1, hOldBmp1);
::SelectObject(hMemDC2, hOldBmp2);
csGrayII.hbmMask = csII.hbmMask;
csGrayII.fIcon = TRUE;
hGrayIcon = ::CreateIconIndirect(&csGrayII);
::DeleteObject(csGrayII.hbmColor);
} // if
::DeleteObject(csII.hbmColor);
::DeleteObject(csII.hbmMask);
::DeleteDC(hMemDC1);
::DeleteDC(hMemDC2);
::ReleaseDC(NULL, hdc);
return hGrayIcon;
} // End of CreateGrayscaleIcon
HICON CreateAlphaIcon(HICON hIcon,int AlphaChange,HBRUSH BackgroundBrush)
{
HDC hMemDC;
DWORD Width, Height;
BITMAPV5HEADER bi;
HBITMAP hBitmap, hOldBitmap;
void *lpBits;
DWORD x,y;
HICON hNewIcon = NULL;
ICONINFO OriginalIconInfos;
if(!::GetIconInfo(hIcon,&OriginalIconInfos))
return NULL;
ICONINFO ii;
ii.fIcon = TRUE; // Change fIcon to TRUE to create an alpha icon
ii.xHotspot = 0;
ii.yHotspot = 0;
if (!AlphaChange)
{
ii.hbmMask = OriginalIconInfos.hbmMask;
ii.hbmColor = OriginalIconInfos.hbmColor;
// Create the alpha cursor with the alpha DIB section.
hNewIcon = ::CreateIconIndirect(&ii);
::DeleteObject(OriginalIconInfos.hbmColor);
::DeleteObject(OriginalIconInfos.hbmMask);
return hNewIcon;
}
Width = OriginalIconInfos.xHotspot*2; // width of Icon
Height = OriginalIconInfos.yHotspot*2; // height of Icon
ZeroMemory(&bi,sizeof(BITMAPV5HEADER));
bi.bV5Size = sizeof(BITMAPV5HEADER);
bi.bV5Width = Width;
bi.bV5Height = Height;
bi.bV5Planes = 1;
bi.bV5BitCount = 32;
bi.bV5Compression = BI_BITFIELDS;
// The following mask specification specifies a supported 32 BPP
// alpha format for Windows XP.
bi.bV5RedMask = 0x00FF0000;
bi.bV5GreenMask = 0x0000FF00;
bi.bV5BlueMask = 0x000000FF;
bi.bV5AlphaMask = 0xFF000000;
HDC hdc;
hdc = ::GetDC(NULL);
// Create the DIB section with an alpha channel.
hBitmap = ::CreateDIBSection(hdc, (BITMAPINFO *)&bi, DIB_RGB_COLORS, (void **)&lpBits, NULL, (DWORD)0);
hMemDC = ::CreateCompatibleDC(hdc);
// select bitmap
hOldBitmap = (HBITMAP)::SelectObject(hMemDC, hBitmap);
// Draw something on the DIB section.
::DrawIconEx(hMemDC,0,0,hIcon,Width,Height,0,
/*0*/ BackgroundBrush, /* some icons needs a background color*/
DI_NORMAL);
// Create an empty mask bitmap.
HBITMAP hMonoBitmap = ::CreateBitmap(Width,Height,1,1,NULL);
DWORD *lpdwPixel;
lpdwPixel = (DWORD *)lpBits;
BYTE bAlpha;
for (x=0;x<Width;x++)
{
for (y=0;y<Height;y++)
{
bAlpha = ( (*lpdwPixel & 0xFF000000) >> 24);
if (AlphaChange<0)
{
if (!bAlpha)
bAlpha = 0xFF;
// increase transparency
bAlpha = (BYTE)__max(bAlpha+AlphaChange,1); // 0 : no transparency
}
else
{
// reduce transparency only for not fully transparent bytes
if (bAlpha)
{
bAlpha = (BYTE)__min(bAlpha+AlphaChange,0xff);
}
}
// Clear the alpha bits
*lpdwPixel &= 0x00FFFFFF;
// Set the new alpha bits
*lpdwPixel |= ( bAlpha <<24) ;
lpdwPixel++;
}
}
ii.hbmMask = hMonoBitmap;
ii.hbmColor = hBitmap;
// Create the alpha cursor with the alpha DIB section.
hNewIcon = ::CreateIconIndirect(&ii);
::SelectObject(hMemDC, hOldBitmap);
::DeleteDC(hMemDC);
::DeleteObject(hBitmap);
::DeleteObject(hMonoBitmap);
::DeleteObject(OriginalIconInfos.hbmColor);
::DeleteObject(OriginalIconInfos.hbmMask);
::ReleaseDC(NULL,hdc);
return hNewIcon;
}
//-----------------------------------------------------------------------------
// Name: CreateAlphaOrGreyscaleIcon
// Object: This function creates an alpha modified or a greyscale icon starting from a given icon.
// The resulting icon will have the same size of the original one.
// Notice the return icon handle must be free by calling ::DeleteObject
// Parameters :
// in : HWND hwnd : hwnd
// int Alpha [-255;255] negative value to increase alpha transparency
// BOOL bGreyscale TRUE to convert to greyscale
// out :
// return : NULL on error hIcon on success
//-----------------------------------------------------------------------------
HICON CreateAlphaOrGreyscaleIcon(HICON hIcon,BOOL bGreyIcon,int AlphaChange,HBRUSH BackgroundBrush)
{
HICON hGreyIcon = hIcon;
HICON hNewIcon;
if (bGreyIcon)
hGreyIcon = CreateGrayscaleIcon(hIcon);
hNewIcon = CreateAlphaIcon(hGreyIcon,AlphaChange,BackgroundBrush);
if (bGreyIcon)
::DestroyIcon(hGreyIcon);
return hNewIcon;
}
//-----------------------------------------------------------------------------
// Name: OnDrawItem
// Object: do picture rendering (full item rendering if MFT_OWNERDRAW)
// Parameters :
// in : HWND hwnd : hwnd
// LPDRAWITEMSTRUCT lpdis : pointer display item info struct
// out :
// return : TRUE if message has been proceed
//-----------------------------------------------------------------------------
BOOL CPopUpMenu::OnDrawItem(HWND hwnd, LPDRAWITEMSTRUCT lpdis)
{
UNREFERENCED_PARAMETER(hwnd);
// assume type is a menu
if (lpdis->CtlType!=ODT_MENU)
return FALSE;
// assume handle match our menu or sub menu
if (this->hPopUpMenu!=(HMENU)lpdis->hwndItem)
{
if (!this->IsSubMenu(this->hPopUpMenu,(HMENU)lpdis->hwndItem))
return FALSE;
}
// assume to have item associated data
if (!lpdis->itemData)
return FALSE;
ICONINFO IconInfo;
// extract icon infos from item data
if (!::GetIconInfo((HICON)lpdis->itemData, &IconInfo))
return FALSE;
UINT Width = IconInfo.xHotspot*2;
UINT Height = IconInfo.yHotspot*2;
// free icon infos
::DeleteObject(IconInfo.hbmColor);
::DeleteObject(IconInfo.hbmMask);
//// render bitmap
//::DrawIconEx(lpdis->hDC, lpdis->rcItem.left, lpdis->rcItem.top,(HICON) lpdis->itemData, Bitmap.bmWidth, Bitmap.bmHeight, 0, NULL, DI_NORMAL);
BOOL bSelected = ( (lpdis->itemState & ODS_SELECTED) == ODS_SELECTED);
BOOL bDisabled = ( (lpdis->itemState & ODS_DISABLED) == ODS_DISABLED);
BOOL bChecked = ( (lpdis->itemState & ODS_CHECKED) == ODS_CHECKED);
//HBITMAP hBmp = LoadBitmap (NULL, MAKEINTRESOURCE(OBM_CHECK));
// bChecked is always FALSE, else we have to play with MFT_OWNERDRAW
HBRUSH CurrentBrush = NULL;
UINT Delta=0;
if (this->bAllowIconsEffects)
Delta =( (bSelected && !bDisabled) ? (CPopUpMenu_ICON_SIZE_INCREMENT-CPopUpMenu_ICON_SHADOW_POSITION_DELTA)/2 : CPopUpMenu_ICON_SIZE_INCREMENT/2 );
// if item is disabled, draw only grey scale icon
if ( bDisabled )
{
HICON hGreyIcon=CreateGrayscaleIcon((HICON) lpdis->itemData);
::DrawIconEx(lpdis->hDC, lpdis->rcItem.left+Delta, lpdis->rcItem.top+Delta,hGreyIcon, Width, Height, 0, NULL, DI_NORMAL);
::DestroyIcon(hGreyIcon);
return TRUE;
}
if (this->bAllowIconsEffects)
{
// if item is checked, draw rectangle around icon
if (bChecked)
{
// get system colors
COLORREF CheckedColor;
COLORREF MenuHilightColor = ::GetSysColor(COLOR_MENUHILIGHT);
COLORREF MenuColor = ::GetSysColor(COLOR_MENU);
// get luminosity difference
int LuminosityDelta = // grey highlighted menu color - grey menu color
(int)((GetRValue(MenuHilightColor) * 0.299) + (GetGValue(MenuHilightColor) * 0.587) + (GetBValue(MenuHilightColor) * 0.114))
- (int)((GetRValue(MenuColor) * 0.299) + (GetGValue(MenuColor) * 0.587) + (GetBValue(MenuColor) * 0.114));
LuminosityDelta/=2;
// forge checked color
CheckedColor = RGB(
__max( __min( GetRValue(MenuHilightColor) - LuminosityDelta , 255 ) , 0 ),
__max( __min( GetGValue(MenuHilightColor) - LuminosityDelta , 255 ) , 0 ),
__max( __min( GetBValue(MenuHilightColor) - LuminosityDelta , 255 ) , 0 )
);
// create pen and select it
HPEN hPen = ::CreatePen(PS_SOLID, 1, (bSelected ? ::GetSysColor(COLOR_MENU) : ::GetSysColor(COLOR_MENUHILIGHT)));
HPEN OldPen= (HPEN)::SelectObject(lpdis->hDC,hPen);
// create brush and select it
CurrentBrush = ::CreateSolidBrush(CheckedColor);
HBRUSH OldBrush = (HBRUSH)::SelectObject(lpdis->hDC,CurrentBrush);
// draw rectangle around icon with selected pen and brush
::Rectangle(lpdis->hDC, lpdis->rcItem.left,lpdis->rcItem.top,lpdis->rcItem.right,lpdis->rcItem.bottom);
// select original brush and pen
::SelectObject(lpdis->hDC,OldBrush);
::SelectObject(lpdis->hDC,OldPen);
}
else
{
if ( bSelected )
CurrentBrush = ::CreateSolidBrush(::GetSysColor(COLOR_MENUHILIGHT));
else
CurrentBrush = ::CreateSolidBrush(::GetSysColor(COLOR_MENU));
}
if ( bSelected )
{
UINT DeltaShadow=(CPopUpMenu_ICON_SIZE_INCREMENT+CPopUpMenu_ICON_SHADOW_POSITION_DELTA)/2;
HICON hAlphaIcon=CreateAlphaOrGreyscaleIcon((HICON) lpdis->itemData,TRUE,-CPopUpMenu_TRANSPARENCY_INCREASE,CurrentBrush);
::DrawIconEx(lpdis->hDC, lpdis->rcItem.left+DeltaShadow, lpdis->rcItem.top+DeltaShadow,hAlphaIcon, Width, Height, 0, NULL, DI_NORMAL);
::DestroyIcon(hAlphaIcon);
}
}
// render bitmap
// ::DrawState(lpdis->hDC, (HBRUSH)NULL, NULL,(LPARAM)(HICON)lpdis->itemData, 0, lpdis->rcItem.left+Delta, lpdis->rcItem.top+Delta, Bitmap.bmWidth, Bitmap.bmHeight, DSS_NORMAL | DST_ICON);
::DrawIconEx(lpdis->hDC, lpdis->rcItem.left+Delta, lpdis->rcItem.top+Delta,(HICON) lpdis->itemData, Width, Height, 0, NULL, DI_NORMAL);
if (CurrentBrush)
::DeleteObject(CurrentBrush);
return TRUE;
}
//-----------------------------------------------------------------------------
// Name: IsSubMenu
// Object: check if hSubMenu is a submenu of hMenu
// Parameters :
// in : HMENU hMenu : a menu handle
// HMENU hSubMenu : sub menu handle to check
// out :
// return : TRUE hMenu is a submenu of current menu
//-----------------------------------------------------------------------------
BOOL CPopUpMenu::IsSubMenu(HMENU hMenu,HMENU hSubMenu)
{
int NbItems=::GetMenuItemCount(hMenu);
MENUITEMINFO mii;
mii.cbSize=sizeof(MENUITEMINFO);
mii.fMask=MIIM_SUBMENU;
for (int Cnt=0;Cnt<NbItems;Cnt++)
{
if (!::GetMenuItemInfo(hMenu,Cnt,TRUE,&mii))
continue;
if (!mii.hSubMenu)
continue;
if (mii.hSubMenu==hSubMenu)
return TRUE;
if (this->IsSubMenu(mii.hSubMenu,hSubMenu))
return TRUE;
}
return FALSE;
}
//-----------------------------------------------------------------------------
// Name: SetMouseRightButtonUpCallback
// Object: set callback for WM_MENURBUTTONUP message
// Parameters :
// in :
// out :
// return : TRUE on success
//-----------------------------------------------------------------------------
BOOL CPopUpMenu::SetMouseRightButtonUpCallback(pfMessageCallback Callback,PVOID UserParam)
{
// check callback validity
if (::IsBadCodePtr((FARPROC)Callback))
return FALSE;
this->MouseRightButtonUpCallback=Callback;
this->MouseRightButtonUpUserParam=UserParam;
return TRUE;
}
//-----------------------------------------------------------------------------
// Name: SetMenuSelectCallback
// Object: set callback for WM_MENUSELECT message
// Parameters :
// in :
// out :
// return : TRUE on success
//-----------------------------------------------------------------------------
BOOL CPopUpMenu::SetMenuSelectCallback(pfMessageCallback Callback,PVOID UserParam)
{
// check callback validity
if (::IsBadCodePtr((FARPROC)Callback))
return FALSE;
this->MenuSelectCallback=Callback;
this->MenuSelectUserParam=UserParam;
return TRUE;
}
//-----------------------------------------------------------------------------
// Name: OnMouseRightButtonUp
// Object: called on WM_MENURBUTTONUP message, call callback if any
// Parameters :
// in :
// out :
// return :
//-----------------------------------------------------------------------------
void CPopUpMenu::OnMouseRightButtonUp(WPARAM wParam, LPARAM lParam)
{
if (this->MouseRightButtonUpCallback)
this->MouseRightButtonUpCallback(wParam,lParam,this->MouseRightButtonUpUserParam);
}
//-----------------------------------------------------------------------------
// Name: OnMenuSelect
// Object: called on WM_MENUSELECT message, call callback if any
// Parameters :
// in :
// out :
// return :
//-----------------------------------------------------------------------------
void CPopUpMenu::OnMenuSelect(WPARAM wParam, LPARAM lParam)
{
if (this->MenuSelectCallback)
this->MenuSelectCallback(wParam,lParam,this->MenuSelectUserParam);
}
//-----------------------------------------------------------------------------
// Name: SubClassWndProc
// Object: subclassing window proc
// Parameters :
// in : WndProc param
// out :
// return :
//-----------------------------------------------------------------------------
LRESULT CALLBACK CPopUpMenu::SubClassWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam,UINT_PTR uIdSubclass,DWORD_PTR dwRefData)
{
UNREFERENCED_PARAMETER(uIdSubclass);
CPopUpMenu* pPopUpMenu=(CPopUpMenu*)dwRefData;
if (!pPopUpMenu)
return ::DefSubclassProc(hWnd,uMsg,wParam,lParam);
switch (uMsg)
{
case WM_MEASUREITEM:
return pPopUpMenu->OnMeasureItem(hWnd, (LPMEASUREITEMSTRUCT) lParam);
case WM_DRAWITEM:
return pPopUpMenu->OnDrawItem(hWnd, (LPDRAWITEMSTRUCT) lParam);
case WM_MENURBUTTONUP:
// FIXME : WM_MENURBUTTONUP is not send for sub menus when they are expanded
pPopUpMenu->OnMouseRightButtonUp(wParam,lParam);
break;
case WM_MENUSELECT:
pPopUpMenu->OnMenuSelect(wParam,lParam);
break;
}
return ::DefSubclassProc(hWnd,uMsg,wParam,lParam);
}