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

📄 chevronhandler.h

📁 一个使用wtl写的完整的多窗口浏览器
💻 H
字号:

#pragma once

inline void MtlEatNextLButtonDownOnChevron(HWND hWndTopLevel, const CRect& rcChevron)
{
	MSG msg;
	if (::PeekMessage(&msg, hWndTopLevel, NULL, NULL, PM_NOREMOVE))
	{
		if (msg.message == WM_LBUTTONDOWN && rcChevron.PtInRect(msg.pt))
			::PeekMessage(&msg, hWndTopLevel, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_REMOVE);
		else if (msg.message == WM_LBUTTONDBLCLK && rcChevron.PtInRect(msg.pt))
			::PeekMessage(&msg, hWndTopLevel, WM_LBUTTONDBLCLK, WM_LBUTTONDBLCLK, PM_REMOVE);
//		else if (msg.message == WM_RBUTTONDOWN && rcChevron.PtInRect(msg.pt))
//			::PeekMessage(&msg, hWndTopLevel, WM_RBUTTONDOWN, WM_RBUTTONDOWN, PM_REMOVE);
//		else if (msg.message == WM_RBUTTONDBLCLK && rcChevron.PtInRect(msg.pt))
//			::PeekMessage(&msg, hWndTopLevel, WM_RBUTTONDBLCLK, WM_RBUTTONDBLCLK, PM_REMOVE);
	}
}

template <class T>
class CChevronHandler
{
public:
	struct _ChevronMenuInfo
	{
		HMENU hMenu;
		LPNMREBARCHEVRON lpnm;
		bool bCmdBar;
	};

// Data members
	CSimpleArray<HMENU> m_arrPopupMenu;

// Methods
	bool PushChevron(LPNMHDR pnmh, HWND hWndMenuOwner)
	{
		_ChevronMenuInfo cmi = { NULL, (LPNMREBARCHEVRON)pnmh, false };
		if(!_PrepareChevronMenu(cmi))
			return false;
		// display a popup menu with hidden items
		_DisplayChevronMenu(cmi, hWndMenuOwner);
		// cleanup
		_CleanupChevronMenu(cmi);

		return true;
	}

// Overridables
	HMENU ChevronHandler_OnGetChevronMenu(int nCmdID, HMENU& hMenuDestroy)
	{
		return NULL;
	}

	void Chevronhandler_OnCleanupChevronMenu()
	{

	}

	BEGIN_MSG_MAP(CChevronHandler<T>)
		NOTIFY_CODE_HANDLER(RBN_CHEVRONPUSHED, OnChevronPushed)
	END_MSG_MAP()

	LRESULT OnChevronPushed(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)
	{
		T* pT = static_cast<T*>(this);

		if (!PushChevron(pnmh, pT->m_hWnd)) {
			bHandled = FALSE;
			return 1;
		}

		return 0;
	}

	bool _PrepareChevronMenu(_ChevronMenuInfo& cmi)
	{
		// get rebar and toolbar
		REBARBANDINFO rbbi;
		rbbi.cbSize = sizeof(REBARBANDINFO);
		rbbi.fMask = RBBIM_CHILD;
		BOOL bRet = (BOOL)::SendMessage(cmi.lpnm->hdr.hwndFrom, RB_GETBANDINFO, cmi.lpnm->uBand, (LPARAM)&rbbi);
		ATLASSERT(bRet);

		// assume the band is a toolbar
		CWindow wnd = rbbi.hwndChild;
		int nCount = (int)wnd.SendMessage(TB_BUTTONCOUNT);
		if(nCount <= 0)		// probably not a toolbar
			return false;

		// check if it's a command bar
		CMenuHandle menuCmdBar = (HMENU)wnd.SendMessage(CBRM_GETMENU);
		cmi.bCmdBar = (menuCmdBar.m_hMenu != NULL);

		// build a menu from hidden items
		CMenuHandle menu;
		bRet = menu.CreatePopupMenu();
		ATLASSERT(bRet);
		RECT rcClient;
		bRet = wnd.GetClientRect(&rcClient);
		ATLASSERT(bRet);
		for(int i = 0; i < nCount; i++)
		{
			TBBUTTON tbb;
			bRet = (BOOL)wnd.SendMessage(TB_GETBUTTON, i, (LPARAM)&tbb);
			ATLASSERT(bRet);
			RECT rcButton;
			bRet = (BOOL)wnd.SendMessage(TB_GETITEMRECT, i, (LPARAM)&rcButton);
			ATLASSERT(bRet);
			bool bEnabled = ((tbb.fsState & TBSTATE_ENABLED) != 0);
			if(rcButton.right > rcClient.right)
			{
				if(tbb.fsStyle & BTNS_SEP)
				{
					if(menu.GetMenuItemCount() > 0)
						menu.AppendMenu(MF_SEPARATOR);
				}
				else if(cmi.bCmdBar)
				{
					TCHAR szBuff[100];
					CMenuItemInfo mii;
					mii.fMask = MIIM_TYPE | MIIM_SUBMENU;
					mii.dwTypeData = szBuff;
					mii.cch = sizeof(szBuff) / sizeof(TCHAR);
					bRet = menuCmdBar.GetMenuItemInfo(i, TRUE, &mii);
					ATLASSERT(bRet);
					// Note: CmdBar currently supports only drop-down items
					ATLASSERT(::IsMenu(mii.hSubMenu));
					bRet = menu.AppendMenu(MF_STRING | MF_POPUP | (bEnabled ? MF_ENABLED : MF_GRAYED), (UINT_PTR)mii.hSubMenu, mii.dwTypeData);
					ATLASSERT(bRet);
				}
				else
				{
					// get button's text
					TCHAR szBuff[100];
					LPTSTR lpstrText = szBuff;
					if(wnd.SendMessage(TB_GETBUTTONTEXT, tbb.idCommand, (LPARAM)szBuff) == -1)
					{
						// no text for this button, try a resource string
						lpstrText = _T("?");
						::LoadString(_Module.GetResourceInstance(), tbb.idCommand, szBuff, sizeof(szBuff) / sizeof(TCHAR));
						for(int n = 0; n < lstrlen(szBuff); n++)
						{
							if(szBuff[n] == _T('\n'))
							{
								lpstrText = &szBuff[n + 1];
								break;
							}
						}
					}

					_InsertMenuItem(wnd.m_hWnd, menu, tbb.idCommand, lpstrText, bEnabled);
//					bRet = menu.AppendMenu(MF_STRING | (bEnabled ? MF_ENABLED : MF_GRAYED), tbb.idCommand, lpstrText);
					ATLASSERT(bRet);
				}
			}
		}

		if(menu.GetMenuItemCount() == 0)	// no hidden buttons after all
		{
			menu.DestroyMenu();
			::MessageBeep((UINT)-1);
			return false;
		}

		cmi.hMenu = menu;
		return true;
	}

	void _DisplayChevronMenu(_ChevronMenuInfo& cmi, HWND hWndMenuOwner)
	{
		T* pT = static_cast<T*>(this);

		// convert chevron rect to screen coordinates
		CWindow wndFrom = cmi.lpnm->hdr.hwndFrom;
		RECT rc = cmi.lpnm->rc;
		wndFrom.ClientToScreen(&rc);
		// set up flags and rect
		UINT uMenuFlags = TPM_LEFTBUTTON | TPM_VERTICAL | TPM_LEFTALIGN | TPM_TOPALIGN | (!AtlIsOldWindows() ? TPM_VERPOSANIMATION : 0);
		TPMPARAMS TPMParams;
		TPMParams.cbSize = sizeof(TPMPARAMS);
		TPMParams.rcExclude = rc;
		// check if this window has a command bar
		HWND hWndCmdBar = (HWND)::SendMessage(pT->m_hWnd, CBRM_GETCMDBAR, 0, 0L);
		if(::IsWindow(hWndCmdBar))
		{
			CBRPOPUPMENU CBRPopupMenu = { sizeof(CBRPOPUPMENU), cmi.hMenu, uMenuFlags, rc.left, rc.bottom, &TPMParams };
			::SendMessage(hWndCmdBar, CBRM_TRACKPOPUPMENU, 0, (LPARAM)&CBRPopupMenu);
		}
		else
		{
			::TrackPopupMenuEx(cmi.hMenu, uMenuFlags, rc.left, rc.bottom, hWndMenuOwner, &TPMParams);
		}
	}

	void _CleanupChevronMenu(_ChevronMenuInfo& cmi)
	{
		T* pT = static_cast<T*>(this);

		CMenuHandle menu = cmi.hMenu;
		// if menu is from a command bar, detach submenus so they are not destroyed
		for(int i = menu.GetMenuItemCount() - 1; i >=0; i--)
			menu.RemoveMenu(i, MF_BYPOSITION);

		pT->Chevronhandler_OnCleanupChevronMenu();

		// clean popups if need
		for(int j = 0; j < m_arrPopupMenu.GetSize(); ++j)
			::DestroyMenu(m_arrPopupMenu[j]);
		m_arrPopupMenu.RemoveAll();

		// destroy menu
		menu.DestroyMenu();
		// convert chevron rect to screen coordinates
		CWindow wndFrom = cmi.lpnm->hdr.hwndFrom;
		RECT rc = cmi.lpnm->rc;
		wndFrom.ClientToScreen(&rc);
		// eat next message if click is on the same button
		MtlEatNextLButtonDownOnChevron(pT->GetTopLevelParent(), rc);
	}

	void _InsertMenuItem(CToolBarCtrl toolbar, CMenuHandle menu, int nIDCmd, const CString& strText, bool bEnabled)
	{
		CVersional<MENUITEMINFO> mii;
		mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE;
		mii.wID = nIDCmd;
		mii.fType = MFT_STRING;
		mii.dwTypeData = (LPTSTR)(LPCTSTR)strText;
		mii.fState = bEnabled ? MFS_ENABLED : MFS_GRAYED;

		CVersional<TBBUTTONINFO> tbi;
		tbi.dwMask = TBIF_STYLE;
		if (toolbar.GetButtonInfo(nIDCmd, &tbi) == -1)
			return;

		if (tbi.fsStyle & BTNS_DROPDOWN || tbi.fsStyle & BTNS_WHOLEDROPDOWN) {
			T* pT = static_cast<T*>(this);

			HMENU hMenuDestroy = NULL;
			CMenuHandle menu = pT->ChevronHandler_OnGetChevronMenu(nIDCmd, hMenuDestroy);
			if (menu.m_hMenu) {
				mii.fMask |= MIIM_SUBMENU;
				mii.hSubMenu = menu.m_hMenu;

				if (hMenuDestroy)
					m_arrPopupMenu.Add(hMenuDestroy);
			}
		}

		menu.InsertMenuItem(-1, TRUE, &mii);
	}
};

⌨️ 快捷键说明

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