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

📄 toolbarhelper.cpp

📁 管理项目进度工具的原代码
💻 CPP
字号:
// ToolbarHelper.cpp: implementation of the CToolbarHelper class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "ToolbarHelper.h"

#include "enbitmap.h"
#include <afxpriv.h>        // for WM_KICKIDLE

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

//////////////////////////////////////////////////////////////////////
// simple helper class for determining whether commands are disabled or not

class CCmdUITH : public CCmdUI
{

public:
	CCmdUITH() { m_bEnabled = TRUE; }
	virtual void Enable(BOOL bOn = TRUE) { m_bEnabled = bOn; }
	virtual void SetCheck(int /*nCheck*/ = 1) {} // dummy
	virtual void SetRadio(BOOL /*bOn*/ = TRUE) {} // dummy
	virtual void SetText(LPCTSTR /*lpszText*/) {} // dummy

public:
	BOOL m_bEnabled;
};

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CToolbarHelper::CToolbarHelper() : m_pToolbar(NULL), m_bMultiline(FALSE), m_nMultilineWidth(200)
{

}

CToolbarHelper::~CToolbarHelper()
{

}

BOOL CToolbarHelper::Initialize(CToolBar* pToolbar, CWnd* pToolbarParent)
{
	if (!pToolbarParent || !HookWindow(*pToolbarParent))
		return FALSE;

	ASSERT_VALID(pToolbar);
	m_pToolbar = pToolbar;

	InitTooltips();

	return TRUE;
}

BOOL CToolbarHelper::Release(BOOL bClearDropBtns) 
{ 
	if (HookWindow(NULL))
	{
		if (bClearDropBtns)
		{
			// iterate the buttons the hard way
			POSITION pos = m_mapTHButtons.GetStartPosition();

			while (pos)
			{
				THButton dm;
				UINT nCmdID = 0;

				m_mapTHButtons.GetNextAssoc(pos, nCmdID, dm);
				ClearDropButton(nCmdID, FALSE);
			}
		}

		m_pToolbar = NULL;
		m_mapTHButtons.RemoveAll();

		return TRUE;
	}

	return FALSE;
}

BOOL CToolbarHelper::SetDropButton(UINT nBtnCmdID, UINT nMenuID, int nSubMenu, UINT nDefCmdID, char cHotkey)
{
	THButton dm;

	if (m_mapTHButtons.Lookup(nBtnCmdID, dm))
		return SetButton(nBtnCmdID, nMenuID, nSubMenu, nDefCmdID, cHotkey, dm.szTip);
	else
		return SetButton(nBtnCmdID, nMenuID, nSubMenu, nDefCmdID, cHotkey, "");
}

BOOL CToolbarHelper::SetTooltip(UINT nBtnCmdID, UINT nIDTip)
{
	CString sTip;

	if (sTip.LoadString(nIDTip))
		return SetTooltip(nBtnCmdID, sTip);

	return FALSE;
}

BOOL CToolbarHelper::SetTooltip(UINT nBtnCmdID, LPCTSTR szTip)
{
	THButton dm;

	if (m_mapTHButtons.Lookup(nBtnCmdID, dm))
		return SetButton(nBtnCmdID, dm.nMenuID, dm.nSubMenu, dm.nDefCmdID, dm.cHotKey, szTip);
	else
		return SetButton(nBtnCmdID, 0, 0, 0, 0, szTip);
}

BOOL CToolbarHelper::SetButton(UINT nBtnCmdID, UINT nMenuID, int nSubMenu, UINT nDefCmdID, char cHotkey, LPCTSTR szTip)
{
	int nIndex = m_pToolbar->CommandToIndex(nBtnCmdID);

	if (nIndex == -1)
		return FALSE;

	if (nMenuID)
	{
		m_pToolbar->GetToolBarCtrl().SetExtendedStyle(TBSTYLE_EX_DRAWDDARROWS);

		DWORD dwStyle = m_pToolbar->GetButtonStyle(nIndex) | TBSTYLE_DROPDOWN;
		m_pToolbar->SetButtonStyle(nIndex, dwStyle);
	}

	THButton dm = { nMenuID, nSubMenu, nDefCmdID, cHotkey };

	ZeroMemory(dm.szTip, sizeof(dm.szTip));
	//fabio_2005
#if _MSC_VER >= 1400
	strncpy_s(dm.szTip, szTip, sizeof(dm.szTip) - 1);
#else
	strncpy(dm.szTip, szTip, sizeof(dm.szTip) - 1);
#endif


	m_mapTHButtons[nBtnCmdID] = dm;

	m_pToolbar->RedrawWindow();

	return TRUE;
}

BOOL CToolbarHelper::ClearDropButton(UINT nBtnCmdID, BOOL bRedraw)
{
	int nIndex = m_pToolbar->CommandToIndex(nBtnCmdID);

	if (nIndex == -1)
		return FALSE;

	DWORD dwStyle = m_pToolbar->GetButtonStyle(nIndex) & ~TBSTYLE_DROPDOWN;
	m_pToolbar->SetButtonStyle(nIndex, dwStyle);

	if (bRedraw)
		m_pToolbar->RedrawWindow();

	return TRUE;
}

BOOL CToolbarHelper::SetDefaultMenuID(UINT nBtnCmdID, UINT nDefCmdID)
{
	THButton dm;
	
	if (m_mapTHButtons.Lookup(nBtnCmdID, dm))
	{
		dm.nDefCmdID = nDefCmdID;
		m_mapTHButtons[nBtnCmdID] = dm;

		return TRUE;
	}

	return FALSE;
}

BOOL CToolbarHelper::DisplayDropMenu(UINT nCmdID, BOOL bPressBtn)
{
	// see if we have a menu for it
	THButton dm;
	
	if (m_mapTHButtons.Lookup(nCmdID, dm) && dm.nMenuID)
	{
		CMenu menu, *pSubMenu;
		
		if (menu.LoadMenu(dm.nMenuID))
		{
			pSubMenu = menu.GetSubMenu(dm.nSubMenu);
			
			if (pSubMenu)
			{
				PrepareMenuItems(pSubMenu, GetCWnd());
				pSubMenu->SetDefaultItem(dm.nDefCmdID);
				
				CRect rItem;
				int nIndex = m_pToolbar->CommandToIndex(nCmdID);

				m_pToolbar->GetItemRect(nIndex, rItem);
				m_pToolbar->ClientToScreen(rItem);
			
				if (bPressBtn)
					m_pToolbar->GetToolBarCtrl().PressButton(nCmdID, TRUE);

				pSubMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON, rItem.left, rItem.bottom, GetCWnd());

				if (bPressBtn)
					m_pToolbar->GetToolBarCtrl().PressButton(nCmdID, FALSE);
				
				return TRUE; // we handled it
			}
		}
	}

	return FALSE;
}

LRESULT CToolbarHelper::WindowProc(HWND hRealWnd, UINT msg, WPARAM wp, LPARAM lp)
{
	switch (msg)
	{
	case WM_NOTIFY:
		{
			LPNMHDR pNMHDR = (LPNMHDR)lp;
			
			switch (pNMHDR->code)
			{
			case TBN_DROPDOWN:
				// check its our toolbar
				if (pNMHDR->hwndFrom == m_pToolbar->GetSafeHwnd())
				{
					// load the menu
					LPNMTOOLBAR pNMTB = (LPNMTOOLBAR)pNMHDR;
					
					if (DisplayDropMenu((UINT)pNMTB->iItem))
						return FALSE; // we handled it
				}
				break;
				
			case TTN_NEEDTEXT:
				{
					// to be thorough we will need to handle UNICODE versions of the message also !!
					TOOLTIPTEXT* pTTT = (TOOLTIPTEXT*)pNMHDR;
					UINT nID = pNMHDR->idFrom;
					
					if (pTTT->uFlags & TTF_IDISHWND) // idFrom is actually the HWND of the tool 
						nID = ::GetDlgCtrlID((HWND)nID);

					// get cursor pos
					CPoint point(::GetMessagePos());
					m_pToolbar->ScreenToClient(&point);
					
					// get tip
					static CString sTipText;
										
					sTipText = GetTip(nID, &point);
					
					if (!sTipText.IsEmpty()) // will be zero on a separator
					{
						pTTT->lpszText = (LPTSTR)(LPCTSTR)sTipText;
						return TRUE;
					}
				}
				break;

			case TTN_SHOW:
				{
					CWnd* pTooltipCtrl = CWnd::FromHandle(pNMHDR->hwndFrom);
					ASSERT (pTooltipCtrl);

					/*int nWidth = */pTooltipCtrl->SendMessage(TTM_SETMAXTIPWIDTH, 0, 
															m_bMultiline ? m_nMultilineWidth : UINT_MAX);
				}
				break;
			}
		}
		break;
	
	case WM_COMMAND:
		{
			HWND hCtrlFrom = (HWND)lp;

			// if m_pToolbar sent the command and we have a mapping for it then
			// change it to the default cmd for that button
			if (hCtrlFrom == *m_pToolbar)
			{
				THButton dm;
				UINT nCmdID = LOWORD(wp);

				if (m_mapTHButtons.Lookup(nCmdID, dm))
				{
					// if we have an enabled default command then send it
					if (dm.nDefCmdID && IsCmdEnabled(dm.nDefCmdID))
						wp = MAKEWPARAM(dm.nDefCmdID, HIWORD(wp));
					else
					{
						BOOL bRes = DisplayDropMenu(nCmdID, TRUE);

						if (bRes)
							return 0L; // we handled it
					}
				}
			}
		}
		break;

	case WM_KICKIDLE:
//	    m_pToolbar->OnUpdateCmdUI((CFrameWnd*)GetCWnd(), FALSE);
		break;

	case WM_DESTROY:
		{
			// must call rest of chain first
			LRESULT lr =  CSubclassWnd::WindowProc(hRealWnd, msg, wp, lp);
			HookWindow(NULL);
			return lr;
		}
	}

	return CSubclassWnd::WindowProc(hRealWnd, msg, wp, lp);
}

LRESULT CToolbarHelper::ScWindowProc(HWND hRealWnd, UINT msg, WPARAM wp, LPARAM lp)
{
	switch (msg)
	{
	case WM_MOUSEMOVE:
	case WM_MOUSELEAVE:
		m_tt.RelayEvent(const_cast<MSG*>(GetCurrentMessage()));
		break;

	case WM_SIZE:
		{
			LRESULT lr = CSubclasser::ScWindowProc(hRealWnd, msg, wp, lp);
			RefreshTooltipRects();
			return lr;
		}
	}

	return CSubclasser::ScDefault(hRealWnd);
}

void CToolbarHelper::InitTooltips()
{
	if (!m_tt.Create(GetCWnd()))
		return;

	// hook the toolbar for mouse messages
	ScHookWindow(m_pToolbar->GetSafeHwnd());

	// turn off default tooltips
	m_pToolbar->SetBarStyle(m_pToolbar->GetBarStyle() & ~CBRS_TOOLTIPS);

	// attach the tooltip ctrl to the toolbar
	m_pToolbar->GetToolBarCtrl().SetToolTips(&m_tt);

	// and activate it
	m_tt.Activate(TRUE);

	// set up tools for each of the toolar buttons
	int nBtnCount = m_pToolbar->GetToolBarCtrl().GetButtonCount();

	for (int nBtn = 0; nBtn < nBtnCount; nBtn++)
	{
		if (m_pToolbar->GetItemID(nBtn) != ID_SEPARATOR)
		{
			CRect rBtn;
			m_pToolbar->GetItemRect(nBtn, rBtn);

			m_tt.AddTool(m_pToolbar, LPSTR_TEXTCALLBACK, rBtn, m_pToolbar->GetItemID(nBtn));
		}
	}
}

void CToolbarHelper::RefreshTooltipRects()
{
	int nBtnCount = m_pToolbar->GetToolBarCtrl().GetButtonCount();

	for (int nBtn = 0; nBtn < nBtnCount; nBtn++)
	{
		if (m_pToolbar->GetItemID(nBtn) != ID_SEPARATOR)
		{
			CRect rBtn;
			m_pToolbar->GetItemRect(nBtn, rBtn);

			m_tt.SetToolRect(m_pToolbar, m_pToolbar->GetItemID(nBtn), rBtn);
		}
	}
}

// static helper
void CToolbarHelper::PrepareMenuItems(CMenu* pMenu, CWnd* pWnd)
{
	// update item states
	CCmdUI state;
	
	state.m_pMenu = pMenu;
	state.m_nIndexMax = pMenu->GetMenuItemCount();
	
	for (state.m_nIndex = 0; state.m_nIndex < state.m_nIndexMax; state.m_nIndex++)
	{
		UINT nCmdID = pMenu->GetMenuItemID(state.m_nIndex);
		
		if (nCmdID == (UINT)-1) // submenu
		{
			CMenu* pSubMenu = pMenu->GetSubMenu(state.m_nIndex);

			if (pSubMenu)
				PrepareMenuItems(pSubMenu, pWnd);
		}
		else if (nCmdID != 0)
		{
			state.m_nID = nCmdID;
			pWnd->OnCmdMsg(state.m_nID, CN_UPDATE_COMMAND_UI, &state, NULL);
		}
	}
}

BOOL CToolbarHelper::IsCmdEnabled(UINT nCmdID) const
{
	CWnd* pParent = CWnd::FromHandle(GetHwnd());

	if (pParent)
	{
		CCmdUITH state;
		
		state.m_nIndexMax = 1;
		state.m_nIndex = 0;
		state.m_nID = nCmdID;

		pParent->OnCmdMsg(nCmdID, CN_UPDATE_COMMAND_UI, &state, NULL);

		return state.m_bEnabled;
	}

	return TRUE;
}

CString CToolbarHelper::GetTip(UINT nID, LPPOINT pPoint) const
{
	if (!nID)
		return ""; // separator

	// are we over the dropbutton?
	BOOL bOverDropBtn = FALSE;

	if (pPoint)
	{
		CSize sizeBtn(m_pToolbar->GetToolBarCtrl().GetButtonSize());
		CRect rButton;

		m_pToolbar->GetToolBarCtrl().GetRect(nID, rButton);
		rButton.left += sizeBtn.cx;

		if (rButton.PtInRect(*pPoint))
			bOverDropBtn = TRUE;
	}

	CString sTip;

	// do we have a mapping for this
	THButton dm;
				
	if (m_mapTHButtons.Lookup(nID, dm))
	{
		if (!bOverDropBtn)
		{
			// try the default item first
			if (dm.nDefCmdID && IsCmdEnabled(dm.nDefCmdID)/* && (dm.nDefCmdID != nID)*/)
			{
				sTip = GetTip(dm.nDefCmdID);

				if (!sTip.IsEmpty())
					return sTip;
			}
		}

		// try override tip
		if (strlen(dm.szTip))
			return dm.szTip;
	}

	return GetTip(nID);
}

CString CToolbarHelper::GetTip(UINT nID)
{
	CString sTip;

	if (nID > 0 && sTip.LoadString(nID) && !sTip.IsEmpty())
	{	
		// tip text starts at '\n' 
		int nStartTip = sTip.Find('\n');
		
		if (nStartTip != -1) 
			sTip = sTip.Right(sTip.GetLength() - nStartTip - 1);

		else // strip '...' if present
			sTip.Replace(".", "");

		sTip.TrimLeft();
		sTip.TrimRight();
	}
	
	return sTip;
}

void CToolbarHelper::EnableMultilineText(BOOL bEnable, int nWidth)
{
	m_bMultiline = bEnable;
	m_nMultilineWidth = nWidth;
}

BOOL CToolbarHelper::ProcessMessage(MSG* pMsg)
{
	if (!IsWindowEnabled() || !m_pToolbar->IsWindowEnabled())
		return FALSE;

	// see if key press matches any hotkey
	if (pMsg->message == WM_SYSKEYDOWN && pMsg->wParam != VK_MENU && (GetKeyState(VK_MENU) & 0x8000))
	{
		int nKey = (int)pMsg->wParam;
		char cLower = 0, cUpper = 0;

		if (islower(nKey))
		{
			cLower = (char)nKey;
			cUpper = (char)toupper(nKey);
		}
		else if (isupper(nKey))
		{
			cUpper = (char)nKey;
			cLower = (char)tolower(nKey);
		}
		else
			cUpper = cLower = (char)nKey;

		// iterate the buttons the hard way
		POSITION pos = m_mapTHButtons.GetStartPosition();

		while (pos)
		{
			THButton dm;
			UINT nCmdID = 0;

			m_mapTHButtons.GetNextAssoc(pos, nCmdID, dm);

			if (nCmdID && (dm.cHotKey == cLower || dm.cHotKey == cUpper))
			{
				DisplayDropMenu(nCmdID, TRUE);
				return TRUE;
			}
		}
	}

	return FALSE;
}

⌨️ 快捷键说明

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