📄 uicoolmenu.cpp
字号:
if (!bSysMenu) {
ConvertMenu(pMenu, nIndex, bSysMenu, m_bShowButtons);
}
}
ConvertMenu(pMenu, nIndex, bSysMenu, m_bShowButtons);
}
//////////////////
// Set the accelerator table used to generate automatic key
// names in menus. Delete previous table if any.
//
void CCoolMenuManager::LoadAccel(HACCEL hAccel)
{
DestroyAccel();
int nAccel;
if (hAccel && (nAccel = CopyAcceleratorTable(hAccel, NULL, 0)) > 0) {
m_pAccel = new ACCEL [nAccel];
ASSERT(m_pAccel);
CopyAcceleratorTable(hAccel, m_pAccel, nAccel);
// Now I have the accelerators. Look over list, linking each command
// ID with its ACCEL structure--i.e., m_mapIDtoAccel[nID] = ACCEL for
// that ID. If more than one ACCEL for a given command (command has more
// than one shortcut), fix up so ACCEL.cmd is offset of prev ACCEL
//
for (int i=0; i<nAccel; i++) {
ACCEL& ac = m_pAccel[i];
ACCEL* pAccel = GetAccel(ac.cmd);
m_mapIDtoAccel.SetAt(ac.cmd, &ac);
ac.cmd = pAccel ? &ac - pAccel : 0; // ac.cmd = offset of prev, or 0
}
}
}
void CCoolMenuManager::ConvertMenu(CMenu *pMenu)
{
ConvertMenu(pMenu, 0, FALSE, TRUE);
}
void CCoolMenuManager::UnconvertMenu(CMenu *pMenu)
{
ConvertMenu(pMenu, 0, FALSE, FALSE);
}
void CCoolMenuManager::ConvertMenuItem(CMenu *pMenu, int iIndex,
bool bRecurse /*= true*/, bool bUnconvert /*= false*/)
{
ASSERT_VALID(pMenu);
CString sItemName;
// get menu item info
TCHAR itemname[_MAX_PATH];
CMenuItemInfo info;
info.fMask = MIIM_SUBMENU | MIIM_DATA | MIIM_ID | MIIM_TYPE;
info.dwTypeData = itemname;
info.cch = sizeof(itemname);
::GetMenuItemInfo(*pMenu, iIndex, TRUE, &info);
// O.S. - ignore separators
if (info.fType & MFT_SEPARATOR)
return;
CMyItemData* pmd = (CMyItemData*)info.dwItemData;
// O.S. - recurse sub-menus
if (bRecurse && info.hSubMenu)
{
ConvertMenu(pMenu->GetSubMenu(iIndex), 0, FALSE, !bUnconvert);
}
if ((info.fType & MFT_OWNERDRAW) && pmd && !pmd->IsMyItemData()) {
CMTRACE(_T("CCoolMenuManager: ignoring foreign owner-draw item\n"));
return;
// owner-draw menu item isn't mine--leave it alone
}
/* // Koji MATSUNAMI 1999.2.23
//
if (bSysMenu && info.wID >= 0xF000) {
CMTRACE(_T("CCoolMenuManager: ignoring sys menu item\n"));
continue; // don't do for system menu commands
}
*/
// now that I have the info, I will modify it
info.fMask = 0; // assume nothing to change
if (!bUnconvert)
{
// I'm showing buttons: convert to owner-draw
if (!(info.fType & MFT_OWNERDRAW))
{
// If not already owner-draw, make it so. NOTE: If app calls
// pCmdUI->SetText to change the text of a menu item, MFC will
// turn the item to MFT_STRING. So I must set it back to
// MFT_OWNERDRAW again. In this case, the menu item data (pmd)
// will still be there.
//
info.fType |= MFT_OWNERDRAW;
info.fMask |= MIIM_TYPE;
if (!pmd || (pmd && !pmd->IsMyItemData()))
{ // if no item data:
if (pmd && !pmd->IsMyItemData())
{
CMyItemData* pnmd = new CMyItemData; // create one
pnmd->pContext = pmd;
pmd = pnmd;
}
else
pmd = new CMyItemData; // create one
ASSERT(pmd); // (I hope)
pmd->fType = info.fType; // handy when drawing
if (info.hSubMenu)
{
int nID;
if (m_mapHMENUtoID.Lookup((void *)info.wID, (WORD&)nID))
{
pmd->iButton = GetButtonIndex(nID);
}
else
{
pmd->iButton = -1;
}
}
else
pmd->iButton = GetButtonIndex(info.wID);
info.dwItemData = (DWORD)pmd; // set in menu item data
info.fMask |= MIIM_DATA; // set item data
}
pmd->text = info.dwTypeData; // copy menu item string
// append accelerators to menu item name
if (m_pAccel && m_bAutoAccel)
AppendAccelName(pmd->text, info.wID);
}
}
else
{
// no buttons -- I'm converting to strings
if (info.fType & MFT_OWNERDRAW) // if ownerdraw:
{
info.fType &= ~MFT_OWNERDRAW; // turn it off
info.fMask |= MIIM_TYPE; // change item type
ASSERT(pmd); // sanity check
sItemName = pmd->text; // save name before deleting pmd
}
else // otherwise:
{
sItemName = info.dwTypeData; // use name from MENUITEMINFO
pmd = NULL;
}
if (pmd) {
// NOTE: pmd (item data) could still be left hanging around even
// if MFT_OWNERDRAW is not set, in case mentioned above where app
// calls pCmdUI->SetText to set text of item and MFC sets the type
// to MFT_STRING.
//
info.dwItemData = (DWORD)pmd->pContext; // item data<-user's context
info.fMask |= MIIM_DATA; // change it
safe_delete(pmd); // and item data too
}
// possibly add accelerator name
if (m_pAccel && m_bAutoAccel && AppendAccelName(sItemName, info.wID))
info.fMask |= MIIM_TYPE; // change item type (string)
if (info.fMask & MIIM_TYPE) {
// if setting name, copy name from CString to buffer and set cch
_tcsncpy(itemname, sItemName, sizeof(itemname));
info.dwTypeData = itemname;
info.cch = sItemName.GetLength();
}
}
// if after all the above, there is anything to change, change it
if (info.fMask) {
CMTRACE(_T("Converting '%s' to %s\n"), itemname,
(info.fType & MFT_OWNERDRAW) ? _T("OWNERDRAW") : _T("STRING"));
SetMenuItemInfo(*pMenu, iIndex, TRUE, &info);
}
}
///////////////////////
// Addition: Philip Oldaker
DWORD CCoolMenuManager::SwitchContextItemData(CMenu *pMenu, int iCmd, DWORD dwItemData /*0*/, BOOL bByPosition /*TRUE*/)
{
CMyItemData* pmd = GetMyItemData(*pMenu,iCmd,bByPosition);
DWORD dwData=0;
if (pmd == NULL)
return dwData;
CMenuItemInfo info;
info.fMask |= MIIM_DATA; // change it
if (pmd->IsMyItemData())
{
dwData= (DWORD)pmd;
info.dwItemData = (DWORD)pmd->pContext;
SetMenuItemInfo(*pMenu, iCmd, bByPosition, &info);
}
else if (dwItemData)
{
CMyItemData *pMyItemData = (CMyItemData*)dwItemData;
if (pMyItemData->IsMyItemData())
{
info.dwItemData = dwItemData;
SetMenuItemInfo(*pMenu, iCmd, bByPosition, &info);
}
}
return dwData;
}
// This may not be the best way of doing it but it seems to work
// Just save the IContextMenu2 pointer on behalf of the windows shell
// and create new item data
void CCoolMenuManager::AddShellContextMenu(CMenu *pMenu, LPCONTEXTMENU lpm, int iIndex)
{
CMyItemData* pmd = GetMyItemData(*pMenu,iIndex,TRUE);
if (pmd == NULL || !pmd->IsMyItemData())
{
DWORD dw = (DWORD)pmd;
pmd = new CMyItemData;
pmd->pContext = (void*)dw;
}
pmd->lpcm = lpm;
pmd->lpcm->AddRef();
SetMyItemData(pmd,*pMenu,iIndex,TRUE);
}
///////////////////////////////
//////////////////
// This rather gnarly function is used both to convert the menu from strings to
// owner-draw and vice versa. In either case, it also appends automagic
// accelerator key names to the menu items, if m_bAutoAccel is TRUE.
//
void CCoolMenuManager::ConvertMenu(CMenu* pMenu, UINT nIndex,
BOOL bSysMenu, BOOL bShowButtons)
{
ASSERT_VALID(pMenu);
UINT i, nItem;
// add/remove the menu to/from list of "converted" menus
HMENU hmenu = pMenu->GetSafeHmenu();
ASSERT(hmenu);
POSITION p = m_menuList.Find(hmenu);
if (!p)
{
if (bShowButtons)
m_menuList.AddHead(hmenu);
}
else
{
if (!bShowButtons)
m_menuList.RemoveAt(p);
}
nItem = pMenu->GetMenuItemCount();
for (i = 0; i < nItem; i++)
{
// loop over each item in menu
ConvertMenuItem(pMenu, i, true, !bShowButtons);
}
}
void *CCoolMenuManager::SetItemData(HMENU hMenu, void *pData, UINT uItem, BOOL bByPosition /*= FALSE*/)
{
CMyItemData *pmd = GetMyItemData(hMenu, uItem, bByPosition);
ASSERT(pmd->IsMyItemData());
void *pOld = pmd->pContext;
pmd->pContext = pData;
SetMyItemData(pmd, hMenu, uItem, bByPosition);
return pOld;
}
void *CCoolMenuManager::GetItemData(HMENU hMenu, UINT uItem, BOOL bByPosition /*= FALSE*/)
{
MENUITEMINFO mii;
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_DATA | MIIM_TYPE;
mii.dwTypeData = NULL;
mii.cch = 0;
if (!::GetMenuItemInfo(hMenu, uItem, bByPosition, &mii))
return NULL;
if (mii.dwItemData == -1) _asm int 3;
CMyItemData *pmd = (CMyItemData *)mii.dwItemData;
if ((mii.fType & MFT_OWNERDRAW) && pmd && pmd->IsMyItemData())
return pmd->pContext;
return pmd;
}
HICON CCoolMenuManager::SetItemIcon(HMENU hMenu, HICON hIcon, UINT uItem, BOOL bByPosition /*= FALSE*/)
{
CMyItemData *pmd = GetMyItemData(hMenu, uItem, bByPosition);
ASSERT(pmd->IsMyItemData());
HICON hOldIcon = pmd->hIcon;
pmd->hIcon = hIcon;
if (hIcon)
pmd->iButton = USES_ICON;
else
pmd->iButton = -1;
SetMyItemData(pmd, hMenu, uItem, bByPosition);
return hOldIcon;
}
HICON CCoolMenuManager::GetItemIcon(HMENU hMenu, UINT uItem, BOOL bByPosition /*= FALSE*/)
{
CMyItemData *pmd = GetMyItemData(hMenu, uItem, bByPosition);
ASSERT(pmd->IsMyItemData());
return pmd->hIcon;
}
void CCoolMenuManager::SetSubMenuIcon(HMENU hSubMenu, int nID)
{
m_mapHMENUtoID[(void *)hSubMenu] = nID;
}
void CCoolMenuManager::UnmanageSubMenu(HMENU hSubMenu)
{
m_mapHMENUtoID.RemoveKey((void *)hSubMenu);
}
//////////////////
// User typed a char into menu. Look for item with & preceeding the char typed.
//
LRESULT CCoolMenuManager::OnMenuChar(UINT nChar, UINT nFlags, CMenu* pMenu)
{
ASSERT_VALID(pMenu);
CMyItemData* pmd = GetMyItemData(*pMenu,0,TRUE);
// Addition: Philip Oldaker
// Pass it on to the shell if this has been set
if (pmd->IsMyItemData() && pmd->lpcm)
{
LRESULT lResult=0;
LPCONTEXTMENU3 lpcm3=NULL;
HRESULT hr = pmd->lpcm->QueryInterface(IID_IContextMenu3,(LPVOID*)&lpcm3);
if (SUCCEEDED(hr))
{
// convert menu back to original item data
UINT nCount = pMenu->GetMenuItemCount();
DWORD *pArrItemData = new DWORD[nCount];
for(UINT i1=0;i1 < nCount;i1++)
pArrItemData[i1] = SwitchContextItemData(pMenu,i1);
lpcm3->HandleMenuMsg2(WM_MENUCHAR,MAKELPARAM(nChar,nFlags),(LPARAM)pMenu->GetSafeHmenu(),&lResult);
lpcm3->Release();
// Convert menu back to back our item data
for(UINT i2=0;i2 < nCount;i2++)
SwitchContextItemData(pMenu,i2,pArrItemData[i2]);
delete []pArrItemData;
}
return lResult;
}
////////////////////////////////
UINT iCurrentItem = (UINT)-1; // guaranteed higher than any command ID
CUIntArray arItemsMatched; // items that match the character typed
UINT nItem = pMenu->GetMenuItemCount();
for (UINT i=0; i< nItem; i++) {
// get menu info
CMenuItemInfo info;
info.fMask = MIIM_DATA | MIIM_TYPE | MIIM_STATE;
::GetMenuItemInfo(*pMenu, i, TRUE, &info);
CMyItemData* pmd = (CMyItemData*)info.dwItemData;
if ((info.fType & MFT_OWNERDRAW) && pmd && pmd->IsMyItemData()) {
CString& text = pmd->text;
int iAmpersand = text.Find(_T('&'));
if (iAmpersand >=0 && toupper(nChar)==toupper(text[iAmpersand+1]))
arItemsMatched.Add(i);
}
if (info.fState & MFS_HILITE)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -