📄 explorermenu.h
字号:
#pragma once
#include <vector>
#include <algorithm>
// for debug
#ifdef _DEBUG
const bool _Mtl_ExplorerMenu_traceOn = false;
#define epmTRACE if (_Mtl_ExplorerMenu_traceOn) ATLTRACE
#else
#define epmTRACE
#endif
// be care, if no element, &array[0] is invalid.
template <class _Key, class _Val>
class CCrasyMap : public CSimpleArray< std::pair<_Key, _Val> >
{
public:
bool FindKey(const _Key& __key)
{
if (GetSize() == 0)
return false;
return end() != std::find_if(begin(), end(), _Finder(__key));
}
void Add(const _Key& __key, const _Val& __val)
{
if (GetSize() == 0) {
CSimpleArray< std::pair<_Key, _Val> >::Add(std::make_pair(__key, __val));
return;
}
std::pair<_Key, _Val>* p = std::find_if(begin(), end(), _Finder(__key));
if (p == end())
CSimpleArray< std::pair<_Key, _Val> >::Add(std::make_pair(__key, __val));
else
(*p).second = __val;
}
_Val Lookup(const _Key& __key)
{
if (GetSize() == 0)
return _Val();
std::pair<_Key, _Val>* p = std::find_if(begin(), end(), _Finder(__key));
if (p != end())
return p->second;
else
return _Val();
}
void Sort()
{
if (GetSize() == 0)
return;
std::sort(begin(), end(), _Compare());
}
std::pair<_Key, _Val>* begin()
{
return &(*this)[0];
}
std::pair<_Key, _Val>* end()
{
return &(*this)[0] + GetSize();
}
// template <class _Key, class _Val>
struct _Finder
{
_Key __aKey;
_Finder(_Key __key) : __aKey(__key) { }
bool operator()(const std::pair<_Key, _Val>& src)
{
return (__aKey == src.first);
}
};
// template <class _Key, class _Val>
struct _Compare
{
bool operator()(const std::pair<_Key, _Val>& x, const std::pair<_Key, _Val>& y)
{
return x.second < y.second;
}
};
};
// Extended styles
#define EMS_ADDITIONALMENUITEM 0x00000001L
#define EMS_ADDITIONALMENUITEMNOSEP 0x00000002L
#define EMS_USER 0x00010000L
#define PASS_MSG_MAP_MENUOWNER_TO_EXPMENU(x) CHAIN_MSG_MAP_MEMBER(x)
/*
class ATL_NO_VTABLE CExplorerMenuImplBase
{
public:
static int s_nMaxMenuItemTextLength;
static int s_nMaxMenuBreakCount;
static void SetMaxMenuItemTextLength(int n)
{
s_nMaxMenuItemTextLength = n;
}
static int GetMaxMenuItemTextLength()
{
return s_nMaxMenuItemTextLength;
}
static void SetMaxMenuBreakCount(int n)
{
s_nMaxMenuBreakCount = n;
}
static int GetMaxMenuBreakCount()
{
return s_nMaxMenuBreakCount;
}
};
__declspec(selectany) int CExplorerMenuImplBase::s_nMaxMenuItemTextLength = 50;
__declspec(selectany) int CExplorerMenuImplBase::s_nMaxMenuBreakCount = 5000;
*/
template <class T>
class ATL_NO_VTABLE CExplorerMenuImpl// : public CExplorerMenuImplBase
{
public:
// Declarations
// Constants
// Data members
DWORD m_dwStyle;
CMenuHandle m_menu;
// CMenu m_menuOriginal;
int m_nOriginalMenuItemCountExceptInsertPointMenuItem;
int m_nOriginalInsertPoint;
int m_nMaxMenuBreakCount;
int m_nMaxMenuItemTextLength;
CString m_strRootDirectoryPath;
CString m_strNoEntries;
CString m_strAdditional;
CSimpleArray<HMENU> m_arrMenuHandle;
int m_nCurrentMenuID;
CCrasyMap<int, CString> m_mapID; // id and file path
CCrasyMap<HMENU, CString> m_mapSubMenu; // menu handle and file path
int m_nInsertPointMenuItemID;
int m_nMinID, m_nMaxID;
CSimpleArray<CString> m_arrIgnoredPath;
// Constructor
CExplorerMenuImpl(int nInsertPointMenuItemID, const CString& strNoEntries = _T("(empty)"),
int nMinID = 0x7000, int nMaxID = 0x7FFF,
const CString& strAdditional = _T("Open This Directory"), int nMaxMenuItemTextLength = 55)
: m_strNoEntries(strNoEntries), m_strAdditional(strAdditional),
m_nInsertPointMenuItemID(nInsertPointMenuItemID),
m_nMinID(nMinID), m_nMaxID(nMaxID),
m_dwStyle(0), m_nMaxMenuBreakCount(5000), m_nMaxMenuItemTextLength(55)
{
m_nCurrentMenuID = m_nMinID;
}
BOOL InstallExplorerMenu(HMENU hMenu)
{
SetMenuHandle(hMenu);
return TRUE;
}
~CExplorerMenuImpl()
{
}
// Overridables
void OnMenuItemInitialUpdate(const CString& strDirPath, CSimpleArray<CMenuItemInfo>& infos)
{
std::sort(_begin(infos), _end(infos), _DefaultMenuItemCompare(*this));
}
void OnExecute(const CString& strFilePath)
{
}
CString OnGetMenuItemText(const CString& strPath)
{
CString str = MtlGetDisplayTextFromPath(strPath);
str = MtlCompactString(str, m_nMaxMenuItemTextLength);
str.Replace(_T("&"), _T("&&"));
return str;
}
// Attributes
void SetMenuHandle(HMENU hMenu)
{
ATLASSERT(::IsMenu(hMenu));
// save original menu infos
ATLASSERT(_FindInsertPoint(hMenu) != -1);// need InsertPointMenuItem
m_nOriginalMenuItemCountExceptInsertPointMenuItem = ::GetMenuItemCount(hMenu) - 1;
m_nOriginalInsertPoint = _FindInsertPoint(hMenu);
m_menu = hMenu;
}
CString GetRootDirectoryPath() const
{
return m_strRootDirectoryPath;
}
void SetRootDirectoryPath(const CString& strDirectoryPath)
{
// ATLASSERT(strDirectoryPath.IsEmpty() == FALSE);
m_strRootDirectoryPath = strDirectoryPath;
}
BOOL LoadAdditionalMenu(_U_STRINGorID menu)
{
return m_menuAdditional.LoadMenu(menu);
}
void SetStyle(DWORD dwStyle)
{
m_dwStyle = dwStyle;
}
DWORD GetStyle() const
{
return m_dwStyle;
}
void AddIgnoredPath(CString& strPath)
{
m_arrIgnoredPath.Add(strPath);
}
void ResetIgnoredPath()
{
m_arrIgnoredPath.RemoveAll();
}
// Methods
/*
template <class _Profile>
void GetProfileExpMenu(_Profile& __profile)
{
DWORD dwStyle, dwLength, dwCount;
LONG lRet = __profile.QueryValue(dwStyle, _T("Style"));
if (lRet != ERROR_SUCCESS)
dwStyle = 0;
lRet = __profile.QueryValue(dwLength, _T("Max_Text_Length"));
if (lRet != ERROR_SUCCESS)
dwLength = 55;
lRet = __profile.QueryValue(dwCount, _T("Max_Break_Count"));
if (lRet != ERROR_SUCCESS)
dwCount = 5000;
SetStyle(dwStyle);
SetMaxMenuItemTextLength(dwLength);
SetMaxMenuBreakCount(dwCount);
}
template <class _Profile>
void WriteProfileExpMenu(_Profile& __profile)
{
__profile.SetValue(GetStyle(), _T("Style"));
__profile.SetValue(GetMaxMenuItemTextLength(), _T("Max_Text_Length"));
__profile.SetValue(GetMaxMenuBreakCount(), _T("Max_Break_Count"));
}
*/
// Message map and handlers
BEGIN_MSG_MAP(CExplorerMenu)
MSG_WM_INITMENUPOPUP(OnInitMenuPopup)
MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect)
COMMAND_RANGE_HANDLER_EX(m_nMinID, m_nMaxID, OnCommandRange)
END_MSG_MAP()
void OnInitMenuPopup(HMENU hmenuPopup, UINT uPos, BOOL fSystemMenu)
{
SetMsgHandled(FALSE);
if (m_strRootDirectoryPath.IsEmpty())
return;
epmTRACE(_T("CExplorerMenu::OnInitMenuPopup : %d\n"), m_nCurrentMenuID);
// Somehow, fSystemMenu is sometimes wrong value, why?
// if (fSystemMenu) {// window menu, do nothing
// epmTRACE(_T(" It's system menu, return");
// return;
// }
if (m_menu.m_hMenu == hmenuPopup) {// root menu
epmTRACE(_T(" It's root menu\n"));
// delayed clean up if menu not clicked
m_mapID.RemoveAll();
// at first, add it to the list
m_arrMenuHandle.Add(hmenuPopup);
// restore original menu (it's need cuz WM_MENUSELECT is not sent if not toplevel menu. for example. chevron menu)
_RestoreOriginalMenu();
// delete insert point menu item
_DeleteInsertPointMenuItem();
int nInsertPoint = m_nOriginalInsertPoint;
_Explore(m_menu, nInsertPoint, m_strRootDirectoryPath);
}
else if (m_arrMenuHandle.Find(hmenuPopup) != -1){// it's my menu
// epmTRACE(_T(" It's %s menu\n"), m_strTestText);
// first, clean up all the menu items
_DeleteAllMenuItems(hmenuPopup);
_Explore(hmenuPopup, 0, _LoadDirectoryPath(hmenuPopup));
SetMsgHandled(TRUE);// eat it!!
}
}
void OnCommandRange(UINT, int nID, HWND hWndCtrl)
{
if (hWndCtrl) {
SetMsgHandled(FALSE);
return;
}
epmTRACE(_T("CExplorerMenu::OnCommandRange : %d\n"), nID);
T* pT = static_cast<T*>(this);
if (CString() != m_mapID.Lookup(nID))
pT->OnExecute(m_mapID.Lookup(nID));
m_mapID.RemoveAll();// delayed clean up.
}
LRESULT OnMenuSelect(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
epmTRACE(_T("CExplorerMenu::OnMenuSelect\n"));
UINT uItem = LOWORD(wParam);
UINT fuFlags = HIWORD(wParam);
HMENU hmenu = (HMENU)lParam;
SetMsgHandled(FALSE);
bHandled = FALSE;// must be, oh my god!!!!!!
// Check if a menu is closing, do a cleanup
if (fuFlags == 0xFFFF && hmenu == NULL) {// menu closing
// NOTE: this message sent only if top level menu!!!
epmTRACE(_T(" Cleanup\n"));
_CleanUpExceptIDMap();
}
// else if (m_arrMenuHandle.Find(hmenu) != -1){// it's my menu
// }
return 0;
}
void _CleanUpExceptIDMap()
{
epmTRACE(_T("CExplorereMenu::_CleanUpExceptIDMap\n"));
// restore original menu
_RestoreOriginalMenu();
m_arrMenuHandle.RemoveAll();
m_mapSubMenu.RemoveAll();
m_nCurrentMenuID = m_nMinID;
}
void _AddNoneMenuItem(CMenuHandle menu, int& nInsertPoint)
{
CMenuItemInfo mii;
mii.fMask = MIIM_STATE | MIIM_TYPE;
mii.fType = MFT_STRING;
mii.fState = MFS_GRAYED;
mii.dwTypeData = (LPTSTR)(LPCTSTR)m_strNoEntries;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -