⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 uicoolmenu.cpp

📁 vc座的资源管理器源代码
💻 CPP
📖 第 1 页 / 共 4 页
字号:
////////////////////////////////////////////////////////////////
// CoolMenu 1997 Microsoft Systems Journal. 
// If this code works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
//
// ==========================================================================  
// HISTORY:   
// ==========================================================================
//    1.01  13 Aug 1998 - Andrew Bancroft [ABancroft@lgc.com] - Since we've already 
//                added the entire toolbar to the imagelist we need to 
//                increment nNextImage even if we didn't add this button to 
//                m_mapIDtoImage in the LoadToolbar() method.
//    1.01a 13 Aug 1998 - Peter Tewkesbury - Added AddSingleBitmap(...)
//                method for adding a single bitmap to a pulldown
//                menu item.
//    1.02  13 Aug 1998 - Omar L Francisco - Fixed bug with lpds->CtlType
//                and lpds->itemData item checking.
//    1.03  12 Nov 1998 - Fixes debug assert in system menu. - Wang Jun
//    1.04  17 Nov 1998 - Fixes debug assert when you maximize a view - Wang Jun
//                window, then try to use the system menu for the view.
//    1.05  09 Jan 1998 - Seain B. Conover [sc@tarasoft.com] - Fix for virtual 
//                key names.
//    1.06  24 Feb 1999 - Michael Lange [michael.home@topdogg.com] - Fix for memory 
//                leak in CMyItemData structure, added a destructor that 
//                calls text.Empty().
//              - Boris Kartamishev [kbv@omegasoftware.com] - Fix for resource
//                ID bug.
//              - Jeremy Horgan [jeremyhorgan@hotmail.com] - During 
//                accelerator key processing OnInitMenuPopup() calls 
//                ConvertMenu() which allocates a new CMyItemData for each 
//                  menu item. This is memory is normally freed by a call to 
//                  OnMenuSelect(), which is not called when processing 
//                accelerator keys. This results in a memory leak. This was
//                fixed by modifying the ~CCoolMenuManager() destructor.
//    1.07  24 Feb 1999 - Koji MATSUNAMI [kmatsu@inse.co.jp] - Fixed problem with 
//                popup menus being drawn correctly as cool menus.
//    1.08  7 Jul 2000 - Philip Oldaker [philip@masmex.com] - Added support for
//				IContextMenu2 as used by the windows shell for owner draw menus
// ==========================================================================
//
/////////////////////////////////////////////////////////////////////////////

#include "StdAfx.h"
#include "UICoolMenu.h"

#include <afxpriv.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define safe_delete(p){if(p){delete p;p=NULL;}}

#define USES_ICON  -2

CCoolMenuManager g_CoolMenuManager;

// helpers
void PLFillRect(CDC& dc, const CRect& rc, COLORREF color);
void PLDrawEmbossed(CDC& dc, CImageList& il, int i,
  CPoint p, BOOL bColor=FALSE);
HBITMAP PLLoadSysColorBitmap(LPCTSTR lpResName, BOOL bMono=FALSE);
inline HBITMAP PLLoadSysColorBitmap(UINT nResID, BOOL bMono=FALSE) {
  return PLLoadSysColorBitmap(MAKEINTRESOURCE(nResID), bMono);
}

// if you want to see extra TRACE diagnostics, set below to TRUE
BOOL CCoolMenuManager::bTRACE = FALSE;

#ifdef _DEBUG
#define CMTRACEFN     \
  CTraceFn __fooble;  \
  if (bTRACE)       \
    TRACE
#define CMTRACE     \
  if (bTRACE)       \
    TRACE
#else
#define CMTRACEFN TRACE
#define CMTRACE   TRACE
#endif

// constants used for drawing
const CXGAP = 1;        // num pixels between button and text
const CXTEXTMARGIN = 2;   // num pixels after hilite to start text
const CXBUTTONMARGIN = 2; // num pixels wider button is than bitmap
const CYBUTTONMARGIN = 2; // ditto for height

// DrawText flags
const DT_MYSTANDARD = DT_SINGLELINE|DT_LEFT|DT_VCENTER;

// identifies owner-draw data as mine
const LONG MYITEMID = MAKELONG(MAKEWORD(_T('m'),_T('i')),MAKEWORD(_T('d'),_T('0')));

// private struct: one of these for each owner-draw menu item
struct CMyItemData {
    long    magicNum;   // magic number identifying me
    CString text;       // item text
    UINT    fType;      // original item type flags
    int     iButton;    // index of button image in image list (or USES_ICON)
    HICON   hIcon;
    void *  pContext;	// item data
	LPCONTEXTMENU lpcm; // if set this will handle menu messages (windows shell)
    CMyItemData()       { lpcm=NULL; magicNum = MYITEMID; iButton = -1; hIcon = 0; pContext = NULL; }
    ~CMyItemData()        { text.Empty(); if (hIcon) ::DestroyIcon(hIcon); if (lpcm) lpcm->Release(); }
    BOOL IsMyItemData()   { return this != NULL  &&  magicNum == MYITEMID; }
};

static CMyItemData *GetMyItemData(HMENU hMenu, UINT uItem, 
                                  BOOL bByPosition = FALSE)
{
    MENUITEMINFO mii;
	ZeroMemory(&mii,sizeof(mii));
    mii.cbSize = sizeof(mii);
    mii.fMask  = MIIM_DATA;
    ::GetMenuItemInfo(hMenu, uItem, bByPosition, &mii);
    return (CMyItemData *)mii.dwItemData;
}

static void SetMyItemData(CMyItemData *pmd, HMENU hMenu, UINT uItem, 
                          BOOL bByPosition = FALSE)
{
    MENUITEMINFO mii;
    mii.cbSize     = sizeof(mii);
    mii.fMask      = MIIM_DATA;
    mii.dwItemData = (DWORD)pmd;
    ::SetMenuItemInfo(hMenu, uItem, bByPosition, &mii);
}


IMPLEMENT_DYNAMIC(CCoolMenuManager, CSubclassWnd)

CCoolMenuManager::CCoolMenuManager()
{
	m_lpcm = NULL;		
	m_szBitmap = CSize(0,0); // will compute later
	m_szButton = CSize(0,0); 
	m_bShowButtons = TRUE;            // show buttons by default
	m_bAutoAccel = TRUE;              // auto accelerators by default
	m_pAccel = NULL;                // no accelerators loaded yet
	m_bUseDrawState = FALSE;          // use DrawEmbossed by default
	m_bDrawDisabledButtonsInColor = FALSE;  // use color for disabled buttons
	FixMFCDotBitmap();
}

CCoolMenuManager::~CCoolMenuManager()
{
  // Jeremy Horgan [jeremyhorgan@hotmail.com]

  while (!m_menuList.IsEmpty()) 
  {
      UnconvertMenu(CMenu::FromHandle((HMENU)m_menuList.RemoveHead()));
  }
  
  Destroy();
}

//////////////////
// Destroy everything. Called from destructor and Refresh.
//
void CCoolMenuManager::Destroy()
{
  m_ilButtons.DeleteImageList();
  m_ilTemp.DeleteImageList();
  m_mapIDtoImage.RemoveAll();
  m_mapHMENUtoID.RemoveAll();
  m_szBitmap = m_szButton = CSize(0,0);
  m_arToolbarID.RemoveAll();
  m_fontMenu.DeleteObject();
  DestroyAccel();
}

/////////////////
// Destroy accelerators
//
void CCoolMenuManager::DestroyAccel()
{
  m_mapIDtoAccel.RemoveAll();   // delete ACCEL entries in map
  safe_delete(m_pAccel);      // delete current accelerators
}

//////////////////
// Call this to install the menu manager. Install(NULL) to un-install.
//
void CCoolMenuManager::Install(CWnd* pFrame)
{
	m_pFrame = pFrame;
	HookWindow(pFrame);   // install message hook
}

void CCoolMenuManager::Uninstall()
{
	m_pFrame = NULL;
	HookWindow((HWND)NULL); 
}

// Addition: Phliip Oldaker
// call this to enable help text on the status bar
void CCoolMenuManager::SetShellContextMenu(LPCONTEXTMENU lpcm,UINT nIDFirst,UINT nIDLast)
{
	m_lpcm = lpcm;
	m_idShellMenuFirst = nIDFirst;
	m_idShellMenuLast = nIDLast;
}

//////////////////
// Load array of toolbar IDs.
//
BOOL CCoolMenuManager::LoadToolbars(const UINT* arID, int n)
{
  ASSERT(arID);
  BOOL bRet = TRUE;
  for (int i=0; i<n; i++)
    bRet |= LoadToolbar(arID[i]);
  return bRet;
}

// structure of RT_TOOLBAR resource
struct TOOLBARDATA {
  WORD wVersion;    // version # should be 1
  WORD wWidth;    // width of one bitmap
  WORD wHeight;   // height of one bitmap
  WORD wItemCount;  // number of items
  WORD items[1];    // array of command IDs, actual size is wItemCount
};

// Addition: Philip Oldaker
CSize CCoolMenuManager::SetButtonSize(CSize &sz)
{
	// Set defaults
	if (sz.cx == 0)
		sz.cx = 16;
	if (sz.cy == 0)
		sz.cy = 15;
	CSize szOld(m_szBitmap);
	m_szBitmap = sz;
	m_szButton = sz + CSize(CXBUTTONMARGIN<<1, CYBUTTONMARGIN<<1);
	return szOld;
}

//////////////////
// Load one toolbar. Assumes bg color is gray.
// 
//  * add toolbar bitmap to image list
//   * add each button ID to button map
//
BOOL CCoolMenuManager::LoadToolbar(UINT nIDToolbar)
{
  // load bitmap
  HBITMAP hbmToolbar = PLLoadSysColorBitmap(nIDToolbar);
  if (!hbmToolbar) {
    TRACE(_T("*** Can't load bitmap for toolbar %d!\n"), nIDToolbar);
    return FALSE;
  }

  // load toolbar
  LPTSTR lpResName = MAKEINTRESOURCE(nIDToolbar);
  HINSTANCE hInst;
  HRSRC hRsrc;
  TOOLBARDATA* ptbd;
  if ((hInst= AfxFindResourceHandle(lpResName, RT_TOOLBAR)) == NULL ||
     (hRsrc= FindResource(hInst, lpResName, RT_TOOLBAR))   == NULL ||
     (ptbd = (TOOLBARDATA*)LoadResource(hInst, hRsrc))     == NULL) {

    TRACE(_T("*** Can't load toolbar %d!\n"), nIDToolbar);
    return FALSE;
  }
  ASSERT(ptbd->wVersion==1);
    
  // OK, I have the bitmap and toolbar. 

  CSize sz(ptbd->wWidth, ptbd->wHeight);
  if (m_szBitmap.cx==0) {
    // First toolbar: initialized bitmap/button sizes and create image list.
    m_szBitmap = sz;
    m_szButton = sz + CSize(CXBUTTONMARGIN<<1, CYBUTTONMARGIN<<1);
    VERIFY(m_ilButtons.Create(sz.cx, sz.cy, ILC_COLOR32|ILC_MASK, 0, 10));
    VERIFY(m_ilTemp.   Create(sz.cx, sz.cy, ILC_COLOR32|ILC_MASK, 0, 10));

  } else if (m_szBitmap != sz) {
    // button sizes different -- oops
    TRACE(_T("*** Toolbar %d button size differs!\n"), nIDToolbar);
    return FALSE;
  }

  m_ilButtons.SetBkColor(::GetSysColor(COLOR_3DFACE));

  // I have a good toolbar: now add bitmap to the image list, and each
  // command ID to m_mapIDtoImage array. Note that LoadSysColorBitmap will
  // change gray -> COLOR_3DFACE, so use that for image list background.
  //
  int iNextImage = m_ilButtons.GetImageCount();
  m_ilButtons.Add(CBitmap::FromHandle(hbmToolbar), GetSysColor(COLOR_3DFACE));
  for (int i = 0; i < ptbd->wItemCount; i++) {
    UINT nID = ptbd->items[i];
    if (nID > 0) {
      if (GetButtonIndex(nID) >= 0) {
        TRACE(_T("*** Duplicate button ID %d ignored\n"), nID);
      } else {
        m_mapIDtoImage.SetAt(nID, (void*)iNextImage);
        TRACE(_T("CCoolMenuManager::LoadToolbar(). Added Menu Id %d, Button Number %d\n"), nID, iNextImage-1);
      }
      // AB. 13-08-98. Since we've already added the entire toolbar to the imagelist
      // we need to increment nNextImage even if we didn't add this button to
      // m_mapIDtoImage.
      iNextImage++;
    }
  }
  m_arToolbarID.Add(nIDToolbar);  // remember toolbar ID for Refresh
  ::DeleteObject(hbmToolbar);
  return TRUE; // success!
}

//////////////////
// Virtual CCoolMenuSubclassWnd window proc. All messages come here before frame
// window. Isn't it cool? Just like in the old days!
//
LRESULT CCoolMenuManager::WindowProc(UINT msg, WPARAM wp, LPARAM lp)
{
  switch(msg) {
      case WM_SYSCOLORCHANGE:
      case WM_SETTINGCHANGE:
        Refresh();
        break;

      case WM_MEASUREITEM:
        if (OnMeasureItem((MEASUREITEMSTRUCT*)lp))
          return TRUE; // handled
        break;

      case WM_DRAWITEM:
        if (OnDrawItem((DRAWITEMSTRUCT*)lp))
          return TRUE; // handled
        break;

      case WM_INITMENUPOPUP:
        // Very important: must let frame window handle it first!
        // Because if someone calls CCmdUI::SetText, MFC will change item to
        // MFT_STRING, so I must change back to MFT_OWNERDRAW.
        //
        CSubclassWnd::WindowProc(msg, wp, lp);
        OnInitMenuPopup(CMenu::FromHandle((HMENU)wp),
          /*(UINT)LOWORD(lp)*/0, (BOOL)HIWORD(lp));
        return 0;

      case WM_MENUSELECT:
        OnMenuSelect((UINT)LOWORD(wp), (UINT)HIWORD(wp), (HMENU)lp);
        break;

      case WM_MENUCHAR:
        LRESULT lr = OnMenuChar((TCHAR)LOWORD(wp), (UINT)HIWORD(wp),
          CMenu::FromHandle((HMENU)lp));
        if (lr!=0)
          return lr;
        break;
  }
  return CSubclassWnd::WindowProc(msg, wp, lp);
}

//////////////////
// Refresh all colors, fonts, etc. For WM_SETTINGCHANGE, WM_SYSCOLORCHANGE.
//
void CCoolMenuManager::Refresh()
{
  // first copy list (array) of toolbar IDs now loaded.
  CUIntArray arToolbarID;
  arToolbarID.Copy(m_arToolbarID);

  // destroy everything
  Destroy();

  // re-load toolbars.
  int nToolbars = arToolbarID.GetSize();

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -