|
|
//=============================================================================
// Implementation for the pseudo menu and menu bar classes used by the
// msinfo control.
//=============================================================================
#include "stdafx.h"
#include "pseudomenu.h"
#include "resource.h"
//=============================================================================
// CPseudoMenu functions.
//=============================================================================
//-----------------------------------------------------------------------------
// Constructor and destructor are really simple.
//-----------------------------------------------------------------------------
CPseudoMenu::CPseudoMenu(LPCTSTR szCaption, COLORREF crNormal, COLORREF crHighlight) : m_hMenu(NULL), m_strCaption(szCaption), m_crNormal(crNormal), m_crHighlight(crHighlight), m_fHighlight(FALSE) { m_rect.left = m_rect.right = m_rect.top = m_rect.bottom = 0; };
CPseudoMenu::~CPseudoMenu() { if (m_hMenu) ::DestroyMenu(m_hMenu); }
//-----------------------------------------------------------------------------
// Get the size of this menu. We'll need the DC for this.
//-----------------------------------------------------------------------------
void CPseudoMenu::GetSize(HDC hdc, int * pcx, int * pcy) { SIZE size;
// Temporarily adding on a find button using the menu bar. This will go
// eventually go away.
CString strCaption(m_strCaption); if (strCaption.Left(1) == _T("\t")) strCaption = strCaption.Mid(1);
if (::GetTextExtentPoint32(hdc, strCaption, strCaption.GetLength(), &size)) { if (pcx) *pcx = size.cx + size.cy; if (pcy) *pcy = size.cy;
m_rect.right = m_rect.left + size.cx + size.cy; m_rect.bottom = m_rect.top + size.cy; } }
//-----------------------------------------------------------------------------
// Move the menu.
//-----------------------------------------------------------------------------
void CPseudoMenu::SetLocation(int cx, int cy) { int cxWidth = m_rect.right - m_rect.left; int cyHeight = m_rect.bottom - m_rect.top;
m_rect.left = cx; m_rect.top = cy; m_rect.right = m_rect.left + cxWidth; m_rect.bottom = m_rect.top + cyHeight; };
//-----------------------------------------------------------------------------
// Update the colors.
//-----------------------------------------------------------------------------
void CPseudoMenu::UpdateColors(COLORREF crNormal, COLORREF crHighlight) { m_crNormal = crNormal; m_crHighlight = crHighlight; }
//-----------------------------------------------------------------------------
// Change the highlight status, and return if an actual change was made.
//-----------------------------------------------------------------------------
BOOL CPseudoMenu::SetHighlight(BOOL fHighlight) { BOOL fDifferent = (m_fHighlight != fHighlight); m_fHighlight = fHighlight; return fDifferent; }
//-----------------------------------------------------------------------------
// Draw the menu caption, using the specified highlight (indicates if the
// mouse is over the menu).
//-----------------------------------------------------------------------------
void CPseudoMenu::Render(HDC hdc) { CDC dc; dc.Attach(hdc);
// Temporarily adding on a find button using the menu bar. This will go
// eventually go away.
// Draw the menu caption.
int cyRectHeight = m_rect.bottom - m_rect.top; int cySmall = (cyRectHeight - 3)/4; int cyMedium = (cyRectHeight - 3)/2; int cyTiny = (cyRectHeight - 3)/6;
// Draw the small arrow icon.
CBrush brush((m_fHighlight) ? m_crHighlight : m_crNormal); CPen pen(PS_SOLID, 1,(m_fHighlight) ? m_crHighlight : m_crNormal); CBrush * pOldBrush = dc.SelectObject(&brush); CPen * pOldPen = dc.SelectObject(&pen);
if (m_strCaption.Left(1) != _T("\t")) { POINT aPoints[] = { {m_rect.left + cySmall, m_rect.top + cyMedium - cyTiny}, {m_rect.left + cyMedium + cySmall, m_rect.top + cyMedium - cyTiny}, {m_rect.left + cyMedium, m_rect.top + cyMedium + cySmall - cyTiny}}; dc.Polygon(aPoints, 3); } else { CGdiObject * pFontOld = dc.SelectStockObject(DEFAULT_GUI_FONT); TEXTMETRIC metrics; dc.GetTextMetrics(&metrics); CSize size = dc.GetTextExtent(m_strCaption.Mid(1)); dc.SelectObject(pFontOld);
POINT aPoints[] = { {m_rect.left, m_rect.top + metrics.tmHeight}, {m_rect.left + size.cx, m_rect.top + metrics.tmHeight}}; dc.Polygon(aPoints, 2); }
dc.SelectObject(pOldBrush); dc.SelectObject(pOldPen);
// Temporarily adding on a find button using the menu bar. This will go
// eventually go away.
CString strCaption(m_strCaption); if (strCaption.Left(1) == _T("\t")) strCaption = strCaption.Mid(1);
CGdiObject * pFontOld = dc.SelectStockObject(DEFAULT_GUI_FONT); COLORREF crTextOld = dc.SetTextColor((m_fHighlight) ? m_crHighlight : m_crNormal); int nBkModeOld = dc.SetBkMode(TRANSPARENT); RECT rectText; ::CopyRect(&rectText, &m_rect);
// The text needs to be offset over by the height (to allow for the arrow icon).
if (m_strCaption.Left(1) != _T("\t")) rectText.left += cyRectHeight;
dc.DrawText(strCaption, strCaption.GetLength(), &rectText, 0); dc.SelectObject(pFontOld); dc.SetTextColor(crTextOld); dc.SetBkMode(nBkModeOld);
dc.Detach(); }
//-----------------------------------------------------------------------------
// Attach the new HMENU and return the existing HMENU.
//-----------------------------------------------------------------------------
HMENU CPseudoMenu::AttachMenu(HMENU hmenu) { HMENU hmenuOriginal = m_hMenu; m_hMenu = hmenu; return (hmenuOriginal); }
//-----------------------------------------------------------------------------
// Display the menu and track the user interaction with it until an item is
// selected. Return the ID of the item selected.
//-----------------------------------------------------------------------------
UINT CPseudoMenu::TrackMenu(HWND hwnd, POINT * pPoint) { // Temporarily adding on a find button using the menu bar. This will go
// eventually go away.
if (m_strCaption.Left(1) == _T("\t")) return ID_EDIT_FIND;
UINT uReturn = 0; const UINT uFlags = TPM_LEFTALIGN | TPM_TOPALIGN | TPM_NONOTIFY | TPM_RETURNCMD | TPM_LEFTBUTTON;
if (m_hMenu) uReturn = ::TrackPopupMenu(m_hMenu, uFlags, pPoint->x, pPoint->y, 0, hwnd, NULL);
return uReturn; }
//=============================================================================
// CPseudoMenuBar functions.
//=============================================================================
//-----------------------------------------------------------------------------
// Constructor and destructor.
//-----------------------------------------------------------------------------
CPseudoMenuBar::CPseudoMenuBar() { m_rect.left = m_rect.right = m_rect.top = m_rect.bottom = 0; for (int i = 0; i < MaxMenus; i++) m_pmenus[i] = NULL; m_ptOrigin.x = m_ptOrigin.y = 5; }
CPseudoMenuBar::~CPseudoMenuBar() { for (int i = 0; i < MaxMenus; i++) if (m_pmenus[i]) delete m_pmenus[i]; }
//-----------------------------------------------------------------------------
// Load the menu specified by the resource ID.
//-----------------------------------------------------------------------------
void CPseudoMenuBar::LoadFromResource(HINSTANCE hinstance, UINT uResourceID, COLORREF crNormal, COLORREF crHighlight) { HMENU hmenu = ::LoadMenu(hinstance, MAKEINTRESOURCE(uResourceID)); if (hmenu) { try { TCHAR szBuffer[MAX_PATH] = _T(""); MENUITEMINFO mii; int index = 0;
mii.cbSize = sizeof(MENUITEMINFO); mii.fMask = MIIM_TYPE; mii.dwTypeData = szBuffer;
HMENU hmenuSub = ::GetSubMenu(hmenu, 0); while (hmenuSub && index < MaxMenus) { mii.cch = MAX_PATH; GetMenuItemInfo(hmenu, 0, TRUE, &mii);
CPseudoMenu * pMenu = new CPseudoMenu(szBuffer, crNormal, crHighlight); pMenu->AttachMenu(hmenuSub); InsertMenu(index++, pMenu); ::RemoveMenu(hmenu, 0, MF_BYPOSITION);
hmenuSub = ::GetSubMenu(hmenu, 0); }
// Temporarily adding on a find button using the menu bar. This will go
// eventually go away. With 196808, it has.
//
// {
// CString strFindButton;
//
// ::AfxSetResourceHandle(_Module.GetResourceInstance());
// strFindButton.LoadString(IDS_FINDBUTTONCAP);
// strFindButton = CString(_T("\t")) + strFindButton;
// CPseudoMenu * pFind = new CPseudoMenu(strFindButton, crNormal, crHighlight);
// InsertMenu(index++, pFind);
// }
::DestroyMenu(hmenu); } catch (...) { ::DestroyMenu(hmenu); } } }
//-----------------------------------------------------------------------------
// Update the colors for each individual menu.
//-----------------------------------------------------------------------------
void CPseudoMenuBar::UpdateColors(COLORREF crNormal, COLORREF crHighlight) { for (int index = 0; index < MaxMenus; index++) if (m_pmenus[index]) m_pmenus[index]->UpdateColors(crNormal, crHighlight); }
//-----------------------------------------------------------------------------
// Insert the pseudo menu into the indicated index.
//-----------------------------------------------------------------------------
void CPseudoMenuBar::InsertMenu(int index, CPseudoMenu * pMenu) { if (index >= 0 && index < MaxMenus) { if (m_pmenus[index]) delete m_pmenus[index]; m_pmenus[index] = pMenu; m_fNeedToComputeRect = TRUE; } }
//-----------------------------------------------------------------------------
// Return a pointer to the requested pseudo menu.
//-----------------------------------------------------------------------------
CPseudoMenu * CPseudoMenuBar::GetMenu(int index) { return (index >= 0 && index < MaxMenus) ? m_pmenus[index] : NULL; }
//-----------------------------------------------------------------------------
// Get the point from which the menu should be launched. This will be
// converted into screen coordinates for the call to TrackMenu. An
// alternative version takes coordinates instead of an index.
//-----------------------------------------------------------------------------
void CPseudoMenuBar::GetMenuPoint(HDC hdc, int index, POINT * pPoint) { RecomputeRect(hdc); if (index >= 0 && index < MaxMenus && m_pmenus[index]) m_pmenus[index]->GetMenuPoint(pPoint); }
void CPseudoMenuBar::GetMenuPoint(HDC hdc, int cx, int cy, POINT * pPoint) { RecomputeRect(hdc); for (int i = 0; i < MaxMenus; i++) if (m_pmenus[i] && m_pmenus[i]->HitTest(cx, cy)) { m_pmenus[i]->GetMenuPoint(pPoint); break; } }
//-----------------------------------------------------------------------------
// Given the coordinates, determine if one of the menus should be drawn with
// a highlight. If the state of one or more menus changes, return TRUE so the
// caller knows the menu bar needs to be re-rendered.
//-----------------------------------------------------------------------------
BOOL CPseudoMenuBar::TrackHighlight(HDC hdc, int cx, int cy) { BOOL fReturn = FALSE;
RecomputeRect(hdc); for (int i = 0; i < MaxMenus; i++) if (m_pmenus[i]) fReturn |= m_pmenus[i]->SetHighlight(m_pmenus[i]->HitTest(cx, cy));
return fReturn; }
//-----------------------------------------------------------------------------
// Set the menu bar so that none of the items are highlighted. Return whether
// we need to be repainted.
//-----------------------------------------------------------------------------
BOOL CPseudoMenuBar::NoHighlight() { BOOL fReturn = FALSE;
for (int i = 0; i < MaxMenus; i++) if (m_pmenus[i]) fReturn |= m_pmenus[i]->SetHighlight(FALSE);
return fReturn; }
//-----------------------------------------------------------------------------
// This is used to actually display the menu and allow the user to choose an
// option from it. The pPoint parameter is the screen point for the menu
// display. The cx and cy parameters are the local coordinates used to find
// the correct menu to show.
//-----------------------------------------------------------------------------
UINT CPseudoMenuBar::TrackMenu(HWND hwnd, POINT * pPoint, int cx, int cy) { for (int i = 0; i < MaxMenus; i++) if (m_pmenus[i] && m_pmenus[i]->HitTest(cx, cy)) return m_pmenus[i]->TrackMenu(hwnd, pPoint); return 0; }
//-----------------------------------------------------------------------------
// Set the origin for the display of the menu bar.
//-----------------------------------------------------------------------------
void CPseudoMenuBar::SetOrigin(HDC hdc, POINT point) { m_ptOrigin = point; m_fNeedToComputeRect = TRUE; RecomputeRect(hdc); }
//-----------------------------------------------------------------------------
// Rendering the menu bar consists of rendering each menu.
//-----------------------------------------------------------------------------
void CPseudoMenuBar::Render(HDC hdc) { RecomputeRect(hdc);
for (int i = 0; i < MaxMenus; i++) if (m_pmenus[i]) m_pmenus[i]->Render(hdc); }
//-----------------------------------------------------------------------------
// A private function used to place all the menus, and compute the bounding
// rectangle.
//-----------------------------------------------------------------------------
void CPseudoMenuBar::RecomputeRect(HDC hdc) { if (!m_fNeedToComputeRect) return; m_fNeedToComputeRect = FALSE;
int cx = 0, cy = 0; int cxCurrent = m_ptOrigin.x;
for (int i = 0; i < MaxMenus; i++) if (m_pmenus[i]) { // Temporarily adding on a find button using the menu bar. This will go
// eventually go away.
if (m_pmenus[i]->GetCaption().Left(1) == _T("\t")) { // Move the button over to the right.
CDC dc; dc.Attach(hdc); CGdiObject * pFontOld = dc.SelectStockObject(DEFAULT_GUI_FONT); CString strCaption = m_pmenus[i]->GetCaption().Mid(1); CSize sizeText = dc.GetTextExtent(strCaption); dc.SelectObject(pFontOld); if ((m_winRect.right - sizeText.cx - 5) > cxCurrent) cxCurrent = m_winRect.right - sizeText.cx - 5; m_pmenus[i]->SetLocation(cxCurrent, m_ptOrigin.y); m_pmenus[i]->GetSize(hdc, &cx, &cy); cxCurrent += cx; dc.Detach(); continue; }
m_pmenus[i]->SetLocation(cxCurrent, m_ptOrigin.y); m_pmenus[i]->GetSize(hdc, &cx, &cy); cxCurrent += cx; }
::SetRect(&m_rect, m_ptOrigin.x, m_ptOrigin.y, m_ptOrigin.x + cxCurrent - 5, m_ptOrigin.y + cy); }
|