Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

462 lines
14 KiB

  1. //=============================================================================
  2. // Implementation for the pseudo menu and menu bar classes used by the
  3. // msinfo control.
  4. //=============================================================================
  5. #include "stdafx.h"
  6. #include "pseudomenu.h"
  7. #include "resource.h"
  8. //=============================================================================
  9. // CPseudoMenu functions.
  10. //=============================================================================
  11. //-----------------------------------------------------------------------------
  12. // Constructor and destructor are really simple.
  13. //-----------------------------------------------------------------------------
  14. CPseudoMenu::CPseudoMenu(LPCTSTR szCaption, COLORREF crNormal, COLORREF crHighlight) :
  15. m_hMenu(NULL),
  16. m_strCaption(szCaption),
  17. m_crNormal(crNormal),
  18. m_crHighlight(crHighlight),
  19. m_fHighlight(FALSE)
  20. {
  21. m_rect.left = m_rect.right = m_rect.top = m_rect.bottom = 0;
  22. };
  23. CPseudoMenu::~CPseudoMenu()
  24. {
  25. if (m_hMenu)
  26. ::DestroyMenu(m_hMenu);
  27. }
  28. //-----------------------------------------------------------------------------
  29. // Get the size of this menu. We'll need the DC for this.
  30. //-----------------------------------------------------------------------------
  31. void CPseudoMenu::GetSize(HDC hdc, int * pcx, int * pcy)
  32. {
  33. SIZE size;
  34. // Temporarily adding on a find button using the menu bar. This will go
  35. // eventually go away.
  36. CString strCaption(m_strCaption);
  37. if (strCaption.Left(1) == _T("\t"))
  38. strCaption = strCaption.Mid(1);
  39. if (::GetTextExtentPoint32(hdc, strCaption, strCaption.GetLength(), &size))
  40. {
  41. if (pcx)
  42. *pcx = size.cx + size.cy;
  43. if (pcy)
  44. *pcy = size.cy;
  45. m_rect.right = m_rect.left + size.cx + size.cy;
  46. m_rect.bottom = m_rect.top + size.cy;
  47. }
  48. }
  49. //-----------------------------------------------------------------------------
  50. // Move the menu.
  51. //-----------------------------------------------------------------------------
  52. void CPseudoMenu::SetLocation(int cx, int cy)
  53. {
  54. int cxWidth = m_rect.right - m_rect.left;
  55. int cyHeight = m_rect.bottom - m_rect.top;
  56. m_rect.left = cx;
  57. m_rect.top = cy;
  58. m_rect.right = m_rect.left + cxWidth;
  59. m_rect.bottom = m_rect.top + cyHeight;
  60. };
  61. //-----------------------------------------------------------------------------
  62. // Update the colors.
  63. //-----------------------------------------------------------------------------
  64. void CPseudoMenu::UpdateColors(COLORREF crNormal, COLORREF crHighlight)
  65. {
  66. m_crNormal = crNormal;
  67. m_crHighlight = crHighlight;
  68. }
  69. //-----------------------------------------------------------------------------
  70. // Change the highlight status, and return if an actual change was made.
  71. //-----------------------------------------------------------------------------
  72. BOOL CPseudoMenu::SetHighlight(BOOL fHighlight)
  73. {
  74. BOOL fDifferent = (m_fHighlight != fHighlight);
  75. m_fHighlight = fHighlight;
  76. return fDifferent;
  77. }
  78. //-----------------------------------------------------------------------------
  79. // Draw the menu caption, using the specified highlight (indicates if the
  80. // mouse is over the menu).
  81. //-----------------------------------------------------------------------------
  82. void CPseudoMenu::Render(HDC hdc)
  83. {
  84. CDC dc;
  85. dc.Attach(hdc);
  86. // Temporarily adding on a find button using the menu bar. This will go
  87. // eventually go away.
  88. // Draw the menu caption.
  89. int cyRectHeight = m_rect.bottom - m_rect.top;
  90. int cySmall = (cyRectHeight - 3)/4;
  91. int cyMedium = (cyRectHeight - 3)/2;
  92. int cyTiny = (cyRectHeight - 3)/6;
  93. // Draw the small arrow icon.
  94. CBrush brush((m_fHighlight) ? m_crHighlight : m_crNormal);
  95. CPen pen(PS_SOLID, 1,(m_fHighlight) ? m_crHighlight : m_crNormal);
  96. CBrush * pOldBrush = dc.SelectObject(&brush);
  97. CPen * pOldPen = dc.SelectObject(&pen);
  98. if (m_strCaption.Left(1) != _T("\t"))
  99. {
  100. POINT aPoints[] = { {m_rect.left + cySmall, m_rect.top + cyMedium - cyTiny},
  101. {m_rect.left + cyMedium + cySmall, m_rect.top + cyMedium - cyTiny},
  102. {m_rect.left + cyMedium, m_rect.top + cyMedium + cySmall - cyTiny}};
  103. dc.Polygon(aPoints, 3);
  104. }
  105. else
  106. {
  107. CGdiObject * pFontOld = dc.SelectStockObject(DEFAULT_GUI_FONT);
  108. TEXTMETRIC metrics;
  109. dc.GetTextMetrics(&metrics);
  110. CSize size = dc.GetTextExtent(m_strCaption.Mid(1));
  111. dc.SelectObject(pFontOld);
  112. POINT aPoints[] = { {m_rect.left, m_rect.top + metrics.tmHeight},
  113. {m_rect.left + size.cx, m_rect.top + metrics.tmHeight}};
  114. dc.Polygon(aPoints, 2);
  115. }
  116. dc.SelectObject(pOldBrush);
  117. dc.SelectObject(pOldPen);
  118. // Temporarily adding on a find button using the menu bar. This will go
  119. // eventually go away.
  120. CString strCaption(m_strCaption);
  121. if (strCaption.Left(1) == _T("\t"))
  122. strCaption = strCaption.Mid(1);
  123. CGdiObject * pFontOld = dc.SelectStockObject(DEFAULT_GUI_FONT);
  124. COLORREF crTextOld = dc.SetTextColor((m_fHighlight) ? m_crHighlight : m_crNormal);
  125. int nBkModeOld = dc.SetBkMode(TRANSPARENT);
  126. RECT rectText;
  127. ::CopyRect(&rectText, &m_rect);
  128. // The text needs to be offset over by the height (to allow for the arrow icon).
  129. if (m_strCaption.Left(1) != _T("\t"))
  130. rectText.left += cyRectHeight;
  131. dc.DrawText(strCaption, strCaption.GetLength(), &rectText, 0);
  132. dc.SelectObject(pFontOld);
  133. dc.SetTextColor(crTextOld);
  134. dc.SetBkMode(nBkModeOld);
  135. dc.Detach();
  136. }
  137. //-----------------------------------------------------------------------------
  138. // Attach the new HMENU and return the existing HMENU.
  139. //-----------------------------------------------------------------------------
  140. HMENU CPseudoMenu::AttachMenu(HMENU hmenu)
  141. {
  142. HMENU hmenuOriginal = m_hMenu;
  143. m_hMenu = hmenu;
  144. return (hmenuOriginal);
  145. }
  146. //-----------------------------------------------------------------------------
  147. // Display the menu and track the user interaction with it until an item is
  148. // selected. Return the ID of the item selected.
  149. //-----------------------------------------------------------------------------
  150. UINT CPseudoMenu::TrackMenu(HWND hwnd, POINT * pPoint)
  151. {
  152. // Temporarily adding on a find button using the menu bar. This will go
  153. // eventually go away.
  154. if (m_strCaption.Left(1) == _T("\t"))
  155. return ID_EDIT_FIND;
  156. UINT uReturn = 0;
  157. const UINT uFlags = TPM_LEFTALIGN | TPM_TOPALIGN | TPM_NONOTIFY | TPM_RETURNCMD | TPM_LEFTBUTTON;
  158. if (m_hMenu)
  159. uReturn = ::TrackPopupMenu(m_hMenu, uFlags, pPoint->x, pPoint->y, 0, hwnd, NULL);
  160. return uReturn;
  161. }
  162. //=============================================================================
  163. // CPseudoMenuBar functions.
  164. //=============================================================================
  165. //-----------------------------------------------------------------------------
  166. // Constructor and destructor.
  167. //-----------------------------------------------------------------------------
  168. CPseudoMenuBar::CPseudoMenuBar()
  169. {
  170. m_rect.left = m_rect.right = m_rect.top = m_rect.bottom = 0;
  171. for (int i = 0; i < MaxMenus; i++)
  172. m_pmenus[i] = NULL;
  173. m_ptOrigin.x = m_ptOrigin.y = 5;
  174. }
  175. CPseudoMenuBar::~CPseudoMenuBar()
  176. {
  177. for (int i = 0; i < MaxMenus; i++)
  178. if (m_pmenus[i])
  179. delete m_pmenus[i];
  180. }
  181. //-----------------------------------------------------------------------------
  182. // Load the menu specified by the resource ID.
  183. //-----------------------------------------------------------------------------
  184. void CPseudoMenuBar::LoadFromResource(HINSTANCE hinstance, UINT uResourceID, COLORREF crNormal, COLORREF crHighlight)
  185. {
  186. HMENU hmenu = ::LoadMenu(hinstance, MAKEINTRESOURCE(uResourceID));
  187. if (hmenu)
  188. {
  189. try
  190. {
  191. TCHAR szBuffer[MAX_PATH] = _T("");
  192. MENUITEMINFO mii;
  193. int index = 0;
  194. mii.cbSize = sizeof(MENUITEMINFO);
  195. mii.fMask = MIIM_TYPE;
  196. mii.dwTypeData = szBuffer;
  197. HMENU hmenuSub = ::GetSubMenu(hmenu, 0);
  198. while (hmenuSub && index < MaxMenus)
  199. {
  200. mii.cch = MAX_PATH;
  201. GetMenuItemInfo(hmenu, 0, TRUE, &mii);
  202. CPseudoMenu * pMenu = new CPseudoMenu(szBuffer, crNormal, crHighlight);
  203. pMenu->AttachMenu(hmenuSub);
  204. InsertMenu(index++, pMenu);
  205. ::RemoveMenu(hmenu, 0, MF_BYPOSITION);
  206. hmenuSub = ::GetSubMenu(hmenu, 0);
  207. }
  208. // Temporarily adding on a find button using the menu bar. This will go
  209. // eventually go away. With 196808, it has.
  210. //
  211. // {
  212. // CString strFindButton;
  213. //
  214. // ::AfxSetResourceHandle(_Module.GetResourceInstance());
  215. // strFindButton.LoadString(IDS_FINDBUTTONCAP);
  216. // strFindButton = CString(_T("\t")) + strFindButton;
  217. // CPseudoMenu * pFind = new CPseudoMenu(strFindButton, crNormal, crHighlight);
  218. // InsertMenu(index++, pFind);
  219. // }
  220. ::DestroyMenu(hmenu);
  221. }
  222. catch (...)
  223. {
  224. ::DestroyMenu(hmenu);
  225. }
  226. }
  227. }
  228. //-----------------------------------------------------------------------------
  229. // Update the colors for each individual menu.
  230. //-----------------------------------------------------------------------------
  231. void CPseudoMenuBar::UpdateColors(COLORREF crNormal, COLORREF crHighlight)
  232. {
  233. for (int index = 0; index < MaxMenus; index++)
  234. if (m_pmenus[index])
  235. m_pmenus[index]->UpdateColors(crNormal, crHighlight);
  236. }
  237. //-----------------------------------------------------------------------------
  238. // Insert the pseudo menu into the indicated index.
  239. //-----------------------------------------------------------------------------
  240. void CPseudoMenuBar::InsertMenu(int index, CPseudoMenu * pMenu)
  241. {
  242. if (index >= 0 && index < MaxMenus)
  243. {
  244. if (m_pmenus[index])
  245. delete m_pmenus[index];
  246. m_pmenus[index] = pMenu;
  247. m_fNeedToComputeRect = TRUE;
  248. }
  249. }
  250. //-----------------------------------------------------------------------------
  251. // Return a pointer to the requested pseudo menu.
  252. //-----------------------------------------------------------------------------
  253. CPseudoMenu * CPseudoMenuBar::GetMenu(int index)
  254. {
  255. return (index >= 0 && index < MaxMenus) ? m_pmenus[index] : NULL;
  256. }
  257. //-----------------------------------------------------------------------------
  258. // Get the point from which the menu should be launched. This will be
  259. // converted into screen coordinates for the call to TrackMenu. An
  260. // alternative version takes coordinates instead of an index.
  261. //-----------------------------------------------------------------------------
  262. void CPseudoMenuBar::GetMenuPoint(HDC hdc, int index, POINT * pPoint)
  263. {
  264. RecomputeRect(hdc);
  265. if (index >= 0 && index < MaxMenus && m_pmenus[index])
  266. m_pmenus[index]->GetMenuPoint(pPoint);
  267. }
  268. void CPseudoMenuBar::GetMenuPoint(HDC hdc, int cx, int cy, POINT * pPoint)
  269. {
  270. RecomputeRect(hdc);
  271. for (int i = 0; i < MaxMenus; i++)
  272. if (m_pmenus[i] && m_pmenus[i]->HitTest(cx, cy))
  273. {
  274. m_pmenus[i]->GetMenuPoint(pPoint);
  275. break;
  276. }
  277. }
  278. //-----------------------------------------------------------------------------
  279. // Given the coordinates, determine if one of the menus should be drawn with
  280. // a highlight. If the state of one or more menus changes, return TRUE so the
  281. // caller knows the menu bar needs to be re-rendered.
  282. //-----------------------------------------------------------------------------
  283. BOOL CPseudoMenuBar::TrackHighlight(HDC hdc, int cx, int cy)
  284. {
  285. BOOL fReturn = FALSE;
  286. RecomputeRect(hdc);
  287. for (int i = 0; i < MaxMenus; i++)
  288. if (m_pmenus[i])
  289. fReturn |= m_pmenus[i]->SetHighlight(m_pmenus[i]->HitTest(cx, cy));
  290. return fReturn;
  291. }
  292. //-----------------------------------------------------------------------------
  293. // Set the menu bar so that none of the items are highlighted. Return whether
  294. // we need to be repainted.
  295. //-----------------------------------------------------------------------------
  296. BOOL CPseudoMenuBar::NoHighlight()
  297. {
  298. BOOL fReturn = FALSE;
  299. for (int i = 0; i < MaxMenus; i++)
  300. if (m_pmenus[i])
  301. fReturn |= m_pmenus[i]->SetHighlight(FALSE);
  302. return fReturn;
  303. }
  304. //-----------------------------------------------------------------------------
  305. // This is used to actually display the menu and allow the user to choose an
  306. // option from it. The pPoint parameter is the screen point for the menu
  307. // display. The cx and cy parameters are the local coordinates used to find
  308. // the correct menu to show.
  309. //-----------------------------------------------------------------------------
  310. UINT CPseudoMenuBar::TrackMenu(HWND hwnd, POINT * pPoint, int cx, int cy)
  311. {
  312. for (int i = 0; i < MaxMenus; i++)
  313. if (m_pmenus[i] && m_pmenus[i]->HitTest(cx, cy))
  314. return m_pmenus[i]->TrackMenu(hwnd, pPoint);
  315. return 0;
  316. }
  317. //-----------------------------------------------------------------------------
  318. // Set the origin for the display of the menu bar.
  319. //-----------------------------------------------------------------------------
  320. void CPseudoMenuBar::SetOrigin(HDC hdc, POINT point)
  321. {
  322. m_ptOrigin = point;
  323. m_fNeedToComputeRect = TRUE;
  324. RecomputeRect(hdc);
  325. }
  326. //-----------------------------------------------------------------------------
  327. // Rendering the menu bar consists of rendering each menu.
  328. //-----------------------------------------------------------------------------
  329. void CPseudoMenuBar::Render(HDC hdc)
  330. {
  331. RecomputeRect(hdc);
  332. for (int i = 0; i < MaxMenus; i++)
  333. if (m_pmenus[i])
  334. m_pmenus[i]->Render(hdc);
  335. }
  336. //-----------------------------------------------------------------------------
  337. // A private function used to place all the menus, and compute the bounding
  338. // rectangle.
  339. //-----------------------------------------------------------------------------
  340. void CPseudoMenuBar::RecomputeRect(HDC hdc)
  341. {
  342. if (!m_fNeedToComputeRect)
  343. return;
  344. m_fNeedToComputeRect = FALSE;
  345. int cx = 0, cy = 0;
  346. int cxCurrent = m_ptOrigin.x;
  347. for (int i = 0; i < MaxMenus; i++)
  348. if (m_pmenus[i])
  349. {
  350. // Temporarily adding on a find button using the menu bar. This will go
  351. // eventually go away.
  352. if (m_pmenus[i]->GetCaption().Left(1) == _T("\t"))
  353. {
  354. // Move the button over to the right.
  355. CDC dc;
  356. dc.Attach(hdc);
  357. CGdiObject * pFontOld = dc.SelectStockObject(DEFAULT_GUI_FONT);
  358. CString strCaption = m_pmenus[i]->GetCaption().Mid(1);
  359. CSize sizeText = dc.GetTextExtent(strCaption);
  360. dc.SelectObject(pFontOld);
  361. if ((m_winRect.right - sizeText.cx - 5) > cxCurrent)
  362. cxCurrent = m_winRect.right - sizeText.cx - 5;
  363. m_pmenus[i]->SetLocation(cxCurrent, m_ptOrigin.y);
  364. m_pmenus[i]->GetSize(hdc, &cx, &cy);
  365. cxCurrent += cx;
  366. dc.Detach();
  367. continue;
  368. }
  369. m_pmenus[i]->SetLocation(cxCurrent, m_ptOrigin.y);
  370. m_pmenus[i]->GetSize(hdc, &cx, &cy);
  371. cxCurrent += cx;
  372. }
  373. ::SetRect(&m_rect, m_ptOrigin.x, m_ptOrigin.y, m_ptOrigin.x + cxCurrent - 5, m_ptOrigin.y + cy);
  374. }