MenuBar.cpp
上传用户:sdxhgc
上传日期:2013-09-14
资源大小:388k
文件大小:58k
源码类别:

通讯编程

开发平台:

Visual C++

  1. // MenuBar.cpp : 
  2. //
  3. #include "stdafx.h"
  4. #include "MenuBar.h"
  5. #include "resource.h"
  6. #include <afxpriv.h>
  7. // pasted from MFC source
  8. #define _AfxGetDlgCtrlID(hWnd)          ((UINT)(WORD)::GetDlgCtrlID(hWnd))
  9. #define HORZF(dw) (dw & CBRS_ORIENT_HORZ)
  10. #define VERTF(dw) (dw & CBRS_ORIENT_VERT)
  11. static void AdjustRectangle(CRect& rect, CPoint pt)
  12. {
  13. int nXOffset = (pt.x < rect.left) ? (pt.x - rect.left) :
  14. (pt.x > rect.right) ? (pt.x - rect.right) : 0;
  15. int nYOffset = (pt.y < rect.top) ? (pt.y - rect.top) :
  16. (pt.y > rect.bottom) ? (pt.y - rect.bottom) : 0;
  17. rect.OffsetRect(nXOffset, nYOffset);
  18. }
  19. #include <math.h>
  20. #ifdef _DEBUG
  21. #define new DEBUG_NEW
  22. #undef THIS_FILE
  23. static char THIS_FILE[] = __FILE__;
  24. #endif
  25. /////////////////////////////////////////////////////////////////////////////
  26. // CMenuBar 
  27. // I want overide EndDrag, but it's not virtual.
  28. // So I have to overide StartDrag!
  29. class CMenuBarDockContext : public CDockContext
  30. {
  31. public:
  32. CMenuBarDockContext(CControlBar* pBar) : CDockContext(pBar) { }
  33. virtual void StartDrag(CPoint pt);
  34. private:
  35. BOOL _Track();
  36. void _EndDrag();
  37. };
  38. namespace {
  39. // hook
  40. CMenuBar* g_pMenuBar = NULL;
  41. HHOOK   g_hMsgHook = NULL;
  42. // message
  43. const UINT MB_SET_MENU_NULL = WM_USER + 1100;
  44. // layout , this will change the height of menubar
  45. const int CXGAP    = 5;
  46. const int CYGAP    = 6;
  47. const int CYGAPVERT    = 3;
  48. const int CXGRIPPER    = 7;
  49. int cyMenuButton = 0;
  50. int cxBorder2 = ::GetSystemMetrics(SM_CXBORDER) * 2;//bWin4 ? CX_BORDER*2 : CX_BORDER;
  51. int cyBorder2 = ::GetSystemMetrics(SM_CYBORDER) * 2;//bWin4 ? CY_BORDER*2 : CY_BORDER;
  52. #ifdef _DEBUG
  53. // if you won't output TRACE in debug mode, make it FALSE;
  54. BOOL bTraceOn = TRUE;
  55. #endif
  56. }
  57. #ifdef _DEBUG
  58. #define LTRACE if (bTraceOn) TRACE
  59. #else
  60. #define LTRACE
  61. #endif
  62. BOOL CMenuBar::m_bMDIApp = FALSE;
  63. BEGIN_MESSAGE_MAP(CMenuBar, CControlBar)
  64. //{{AFX_MSG_MAP(CMenuBar)
  65. ON_WM_LBUTTONDOWN()
  66. ON_WM_MOUSEMOVE()
  67. ON_WM_TIMER()
  68. ON_WM_KILLFOCUS()
  69. ON_WM_CREATE()
  70. ON_WM_LBUTTONUP()
  71. ON_WM_DESTROY()
  72. ON_MESSAGE(MB_SET_MENU_NULL, OnSetMenuNull)
  73. ON_MESSAGE(WM_SYSCOLORCHANGE, OnSettingChange)
  74. //}}AFX_MSG_MAP
  75. ON_MESSAGE(WM_SETTINGCHANGE, OnSettingChange)
  76. END_MESSAGE_MAP()
  77. CMenuBar::CMenuBar()
  78. {
  79. m_nCurIndex  = -1;
  80. m_nTrackingState = none;
  81. m_bProcessRightArrow = m_bProcessLeftArrow = TRUE;
  82. m_bIgnoreAlt = FALSE;
  83. m_bDown  = FALSE;
  84. m_hMenu  = NULL;
  85. m_nIDEvent  = NULL;
  86. m_bIcon  = FALSE;
  87. m_bMDIMaximized = FALSE;
  88. m_hWndMDIClient = NULL;
  89. m_hWndActiveChild = NULL;
  90. m_pMenuIcon = NULL;
  91. m_pMenuControl = NULL;
  92. m_nCmdShow = SW_SHOW;
  93. }
  94. BOOL CMenuBar::Create(CWnd* pParentWnd, DWORD dwStyle, UINT nID)
  95. {
  96. ASSERT_VALID(pParentWnd); // must have a parent
  97. ASSERT (!((dwStyle & CBRS_SIZE_FIXED) && (dwStyle & CBRS_SIZE_DYNAMIC)));
  98. // save the style
  99. m_dwStyle = dwStyle & CBRS_ALL;   // fixed by Mark Gentry, thanx!
  100. m_dwStyle |= CBRS_SIZE_DYNAMIC;
  101. CString strClass = AfxRegisterWndClass(
  102. CS_HREDRAW | CS_VREDRAW |
  103. CS_DBLCLKS, // don't forget!
  104. AfxGetApp()->LoadStandardCursor(IDC_ARROW),
  105. (HBRUSH)(COLOR_BTNFACE + 1));
  106. return CWnd::Create(strClass, _T("MenuBar"), dwStyle, CRect(), pParentWnd, nID);
  107. }
  108. int CMenuBar::OnCreate(LPCREATESTRUCT lpCreateStruct) 
  109. {
  110. if (CControlBar::OnCreate(lpCreateStruct) == -1)
  111. return -1;
  112. CWnd* pFrame = GetOwner();
  113. ASSERT_VALID(pFrame);
  114. // hook frame window to trap WM_MENUSELECT
  115. m_hookFrame.Install(this, pFrame->GetSafeHwnd());
  116. // If this is an MDI app, hook client window to trap WM_MDISETMENU
  117. if (pFrame->IsKindOf(RUNTIME_CLASS(CMDIFrameWnd))) {
  118. CMenuBar::m_bMDIApp = TRUE;
  119. m_hWndMDIClient = ((CMDIFrameWnd*)pFrame)->m_hWndMDIClient;
  120. ASSERT(m_hWndMDIClient);
  121. m_hookMDIClient.Install(this, m_hWndMDIClient);
  122. }
  123. // my own DockContext!
  124. m_pDockContext = new CMenuBarDockContext(this);
  125. return 0;
  126. }
  127. BOOL CMenuBar::InitItems()
  128. {
  129. ASSERT(m_hMenu);
  130. // clean up all items
  131. DeleteItems();
  132. // a little suitable
  133. int nCount = ::GetMenuItemCount(m_hMenu);
  134. ASSERT(nCount > 0);
  135. m_arrItem.SetSize(nCount);
  136. if (!CMenuButton::InitCommonResource()) {
  137. //TRACE("Failed to create bar resourcen");
  138. return FALSE;
  139. }
  140. // buttons
  141. for (int i = 0; i < nCount; ++i) {
  142. m_arrItem[i] = new CMenuButton(m_hMenu, i);
  143. }
  144. cyMenuButton = m_arrItem[0]->m_sizeHorz.cy;
  145. // icon
  146. m_pMenuIcon = new CMenuIcon(this);
  147. m_arrItem.InsertAt(0, m_pMenuIcon);
  148. // frame control
  149. m_pMenuControl = new CMenuControl(this);
  150. m_arrItem.Add(m_pMenuControl);
  151.     
  152. // reinitializing
  153. m_hWndActiveChild = GetActiveChildWnd(m_bMDIMaximized);
  154. if (m_hWndActiveChild) {// re set 
  155. m_pMenuIcon->OnActivateChildWnd(m_hWndActiveChild);
  156. }
  157. if (m_bMDIMaximized) {
  158. m_pMenuIcon->Validate(TRUE);
  159. m_pMenuControl->Validate(TRUE);
  160. }
  161. return TRUE;
  162. }
  163. BOOL CMenuBar::LoadMenuBar(UINT nIDResource)
  164. {
  165. if (m_hMenu) {
  166. ::DestroyMenu(m_hMenu);
  167. m_hMenu = NULL;
  168. }
  169. ASSERT_VALID(m_pDockSite);
  170. if (m_pDockSite->GetMenu()) {
  171. PostMessage(MB_SET_MENU_NULL, (WPARAM)m_pDockSite->GetSafeHwnd());
  172. }
  173. m_hMenu = ::LoadMenu(AfxGetInstanceHandle(), MAKEINTRESOURCE(nIDResource));
  174. if (m_hMenu == NULL) {
  175. //TRACE("Failed to load menun");
  176. return FALSE;
  177. }
  178. return InitItems();
  179. }
  180. void CMenuBar::RefreshBar()
  181. {
  182. InvalidateRect(NULL);
  183. CFrameWnd* pFrame = (CFrameWnd*)GetOwner();
  184. ASSERT_VALID(pFrame);
  185. ASSERT(pFrame->IsFrameWnd());
  186. pFrame->RecalcLayout();
  187. // floating frame
  188. pFrame = GetParentFrame();
  189. if (pFrame->IsKindOf(RUNTIME_CLASS(CMiniFrameWnd)))
  190. pFrame->RecalcLayout();
  191. }
  192. HMENU CMenuBar::LoadMenu(HMENU hMenu, HMENU hWindowMenu)
  193. {
  194. LTRACE("CMenuBar::LoadMenun");
  195. UINT iPrevID=(UINT)-1;
  196. ASSERT(::IsMenu(hMenu));
  197. ASSERT_VALID(this);
  198. CFrameWnd* pFrame = GetParentFrame();
  199. if (::GetMenu(pFrame->GetSafeHwnd()) != NULL) {
  200. // not to make MFC ignore SetMenu(NULL), post it.
  201. PostMessage(MB_SET_MENU_NULL, (WPARAM)pFrame->GetSafeHwnd());
  202. }
  203. HMENU hOldMenu = m_hMenu;
  204. m_hMenu = hMenu; // menu is shared with MFC
  205. // initialize Items 
  206. VERIFY(InitItems());
  207. if (hMenu) {
  208. m_hWindowMenu = hWindowMenu;
  209. RefreshBar(); // and menubar itself
  210. }
  211. return hOldMenu;
  212. }
  213. CMenuBar::~CMenuBar()
  214. {
  215. if (m_bMDIApp == FALSE && m_hMenu != NULL)
  216. ::DestroyMenu(m_hMenu);
  217. }
  218. /////////////////////////////////////////////////////////////////////////////
  219. // CMenuBar 傾僀僥儉偺忣曬
  220. /////////////////////////////////////////////////////////////////////////////
  221. // CMenuBar 傾僀僥儉昤夋
  222. void CMenuBar::UpdateBar(TrackingState nState, int nNewIndex)
  223. {
  224. if (m_nTrackingState == buttonmouse)
  225. m_bIgnoreAlt = FALSE; // if prev state is BUTTONMOUSE, always should be FALSE!
  226. m_nTrackingState = nState;
  227. #ifdef _DEBUG
  228. // static LPCTSTR lpszStates[] = { _T("NONE"), _T("BUTTON"), _T("POPUP"), _T("BUTTONMOUSE") };
  229. // LTRACE(_T("CMenuBar::UpdateBar state to %s, button=%dn"),
  230. // lpszStates[nState], nNewIndex);
  231. #endif
  232. // clean up
  233. if (IsValidIndex(m_nCurIndex)) {
  234. CDC* pDC = GetDC();
  235. m_arrItem[m_nCurIndex]->SetState(CMenuButton::none);
  236. m_arrItem[m_nCurIndex]->Update(pDC);
  237. CRect rcCross = m_pMenuControl->m_rcItem & m_arrItem[m_nCurIndex]->m_rcItem;
  238. if (!rcCross.IsRectEmpty()) {
  239. m_pMenuControl->ForceDrawControl(pDC);
  240. }
  241. ReleaseDC(pDC);
  242. m_nCurIndex = -1;
  243. }
  244. if (nState != none) {
  245. ASSERT(IsValidIndex(nNewIndex));
  246. m_nCurIndex = nNewIndex;
  247. CDC* pDC = GetDC();
  248. if (nState == button || nState == buttonmouse) {
  249. m_arrItem[m_nCurIndex]->SetState(CMenuButton::hot);
  250. m_arrItem[m_nCurIndex]->Update(pDC);
  251. }
  252. else if (nState == popup) {
  253. m_arrItem[m_nCurIndex]->SetState(CMenuButton::select);
  254. m_arrItem[m_nCurIndex]->Update(pDC);
  255. }
  256. CRect rcCross = m_pMenuControl->m_rcItem & m_arrItem[m_nCurIndex]->m_rcItem;
  257. if (!rcCross.IsRectEmpty()) {
  258. m_pMenuControl->ForceDrawControl(pDC);
  259. }
  260. ReleaseDC(pDC);
  261. }
  262. else {
  263. // must be default parameter
  264. ASSERT(nNewIndex == -1);
  265. }
  266. m_bProcessRightArrow = m_bProcessLeftArrow = TRUE;
  267. }
  268. /////////////////////////////////////////////////////////////////////////////
  269. // CMenuBar 儊僢僙乕僕 僴儞僪儔
  270. int CMenuBar::HitTestOnTrack(CPoint point)
  271. {
  272. for (int i = 0; i < GetItemCount(); ++i) {
  273. CMenuItem* pItem = m_arrItem[i];
  274. CRect rcItem = pItem->GetItemRect();
  275. if (pItem->IsValid() && pItem->CanTrack() &&
  276. rcItem.PtInRect(point))
  277. return i;
  278. }
  279. return -1;
  280. }
  281. void CMenuBar::OnLButtonDown(UINT nFlags, CPoint point) 
  282. {
  283. // LTRACE("CMenuBar::OnLButtonDownn");
  284. ASSERT(m_pMenuControl);
  285. if (m_pMenuControl->OnMouseMsg(WM_LBUTTONDOWN, nFlags, point)) {
  286. return; // eat it!
  287. }
  288. int nIndex = HitTestOnTrack(point);
  289. if (IsValidIndex(nIndex) && m_arrItem[nIndex]->CanTrack()) {
  290. /* HMENU hSubMenu = ::GetSubMenu(m_hMenu, nIndex);
  291. if (hSubMenu == NULL) {
  292. UpdateWindow(); // force to repaint
  293. CDC* pDC = GetDC();
  294. m_arrItem[m_nCurIndex]->SetState(CMenuButton::select);
  295. m_arrItem[nIndex]->Update(pDC);
  296. ReleaseDC(pDC);
  297. m_bDown = TRUE;
  298. }
  299. else {
  300. TrackPopup(nIndex);
  301. }
  302. */
  303. TrackPopup(nIndex);
  304. return; // eat it!
  305. }
  306. CControlBar::OnLButtonDown(nFlags, point);
  307. }
  308. void CMenuBar::OnMouseMove(UINT nFlags, CPoint point) 
  309. {
  310. // TRACE("CMenuBar::OnMouseMoven");
  311. if (!IsTopParentActive() || !GetTopLevelParent()->IsWindowEnabled()) {
  312. // window is not active, ignore
  313. CControlBar::OnMouseMove(nFlags, point);
  314. return;
  315. }
  316. ASSERT(m_pMenuControl);
  317. if (m_pMenuControl->OnMouseMsg(WM_MOUSEMOVE, nFlags, point)) {
  318. CControlBar::OnMouseMove(nFlags, point);
  319. return;
  320. }
  321. int nIndex = HitTestOnTrack(point);
  322. if (IsValidIndex(nIndex)) {
  323. if (m_nCurIndex == -1 || m_nCurIndex != nIndex) { // other button
  324. UpdateBar(buttonmouse, nIndex); // button tracked with mouse
  325. // I wanna know when mouse is away,
  326. // but SetCapture makes ALT+F4 uncatchable
  327. // and WM_CAPTURECHANGED is never sent(why?), so we have to set timer
  328. _KillTimer();
  329. m_nIDEvent = SetTimer(1, 250, 0);
  330. }
  331. }
  332. else {
  333. UpdateBar();
  334. }
  335. CControlBar::OnMouseMove(nFlags, point);
  336. }
  337. void CMenuBar::OnTimer(UINT nIDEvent) 
  338. {
  339. if( nIDEvent == m_nIDEvent && m_nTrackingState == buttonmouse) {
  340. CPoint pt; ::GetCursorPos(&pt);
  341. CRect rect;
  342. GetWindowRect(&rect);
  343. if (!rect.PtInRect(pt)) {
  344. UpdateBar();
  345. _KillTimer();
  346. }
  347. }
  348. CControlBar::OnTimer(nIDEvent);
  349. }
  350. void CMenuBar::OnKillFocus(CWnd* pNewWnd) 
  351. {
  352. CControlBar::OnKillFocus(pNewWnd);
  353. // TODO: 
  354. UpdateBar();
  355. }
  356. LRESULT CMenuBar::OnSetMenuNull(WPARAM wParam, LPARAM)
  357. {
  358. HWND hWnd = (HWND)wParam;
  359. ASSERT(::IsWindow(hWnd));
  360. ::SetMenu(hWnd, NULL);
  361. return 0;
  362. }
  363. LRESULT CMenuBar::OnSettingChange(WPARAM wParam, LPARAM lParam)
  364. {
  365. InitItems();
  366. CFrameWnd* pFrame = GetParentFrame();
  367. ASSERT_VALID(pFrame);
  368. pFrame->RecalcLayout();
  369. return 0;
  370. }
  371. /////////////////////////////////////////////////////////////////////////////
  372. // CMenuBar
  373. void CMenuBar::OnMenuSelect(HMENU hMenu, UINT nIndex)
  374. {
  375. if (m_nTrackingState == popup) {
  376. m_bProcessRightArrow = (::GetSubMenu(hMenu, nIndex) == NULL);
  377. HMENU hSubMenu = ::GetSubMenu(hMenu, m_nCurIndex);
  378. if (hSubMenu == NULL)
  379. return;
  380. m_bProcessLeftArrow = (hMenu == hSubMenu);
  381. }
  382. }
  383. LRESULT CALLBACK CMenuBar::MenuInputFilter(int code, WPARAM wParam, LPARAM lParam)
  384. {
  385. return (
  386. code == MSGF_MENU &&
  387. g_pMenuBar &&
  388. g_pMenuBar->OnMenuInput( *((MSG*)lParam) )
  389. ) ? TRUE : CallNextHookEx(g_hMsgHook, code, wParam, lParam);
  390. }
  391. void CMenuBar::TrackPopup(int nIndex)
  392. {
  393. ASSERT_VALID(this);
  394. m_nCurIndex = nIndex;
  395. m_bLoop = TRUE;
  396. while (m_bLoop == TRUE) {
  397. UpdateWindow(); // force to repaint when button hidden by other window
  398. UpdateBar(popup, m_nCurIndex);
  399. // install hook
  400. ASSERT(g_pMenuBar == NULL);
  401. g_pMenuBar = this;
  402. ASSERT(g_hMsgHook == NULL);
  403. m_bLoop = FALSE;
  404. g_hMsgHook = ::SetWindowsHookEx(WH_MSGFILTER,
  405. MenuInputFilter, NULL, AfxGetApp()->m_nThreadID);// m_bLoop may become TRUE
  406. // popup!!
  407. m_nTrackingState = popup;
  408. m_arrItem[m_nCurIndex]->TrackPopup(this);
  409. // uninstall hook
  410. ::UnhookWindowsHookEx(g_hMsgHook);
  411. g_hMsgHook = NULL;
  412. g_pMenuBar = NULL;
  413. }
  414. UpdateBar();
  415. }
  416. BOOL CMenuBar::OnMenuInput(MSG& m)
  417. {
  418. ASSERT_VALID(this);
  419. int nMsg = m.message;
  420. CPoint pt = m.lParam;
  421. ScreenToClient(&pt);
  422. switch (nMsg) {
  423. case WM_MOUSEMOVE:
  424. if (pt != m_ptMouse) {
  425. int nIndex = HitTestOnTrack(pt);
  426. if (IsValidIndex(nIndex) && nIndex != m_nCurIndex) {
  427. // defferent button clicked
  428. GetOwner()->PostMessage(WM_CANCELMODE); // destroy popupped menu
  429. UpdateBar(); // clean up
  430. m_nCurIndex = nIndex;
  431. m_bLoop = TRUE; // continue loop
  432. }
  433. m_ptMouse = pt;
  434. }
  435. break;
  436. case WM_LBUTTONDOWN:
  437. if (HitTestOnTrack(pt) != -1 && HitTestOnTrack(pt) == m_nCurIndex) {
  438. // same button clicked
  439. GetOwner()->PostMessage(WM_CANCELMODE); // destroy popupped menu
  440. UpdateBar(button, m_nCurIndex);
  441. return TRUE; // eat it!
  442. }
  443. break;
  444. case WM_KEYDOWN: {
  445. TCHAR vKey = m.wParam;
  446. if (m_dwStyle & CBRS_ORIENT_VERT) { // if vertical
  447. break; // do nothing
  448. }
  449. if ((vKey == VK_LEFT  && m_bProcessLeftArrow) ||
  450. (vKey == VK_RIGHT && m_bProcessRightArrow)) {
  451. // no submenu
  452. int nNewIndex = GetNextOrPrevButton(m_nCurIndex, vKey==VK_LEFT);
  453. GetOwner()->PostMessage(WM_CANCELMODE); // destroy popupped menu
  454. UpdateBar();
  455. m_nCurIndex = nNewIndex;
  456. m_bLoop = TRUE; // continue loop
  457. return TRUE; // eat it!
  458. }
  459. }
  460. break;
  461. case WM_SYSKEYDOWN:
  462. // LTRACE("    m_bIgnore = TRUEn");
  463. m_bIgnoreAlt = TRUE; // next SysKeyUp will be ignored
  464. break;
  465. }
  466. return FALSE; // pass along...
  467. }
  468. BOOL CMenuBar::TranslateFrameMessage(MSG* pMsg)
  469. {
  470. ASSERT_VALID(this);
  471. ASSERT(pMsg);
  472. UINT nMsg = pMsg->message;
  473. if (WM_LBUTTONDOWN <= nMsg && nMsg <= WM_MOUSELAST) {
  474. if (pMsg->hwnd != m_hWnd && m_nTrackingState > 0) {
  475. // clicked outside
  476. UpdateBar();
  477. }
  478. }
  479. else if (nMsg == WM_SYSKEYDOWN || nMsg == WM_SYSKEYUP || nMsg == WM_KEYDOWN) {
  480. BOOL bAlt = HIWORD(pMsg->lParam) & KF_ALTDOWN; // Alt key presed?
  481. TCHAR vkey = pMsg->wParam; // + X key
  482. if (vkey == VK_MENU ||
  483. (vkey == VK_F10 && !((GetKeyState(VK_SHIFT) & 0x80000000) ||
  484.                    (GetKeyState(VK_CONTROL) & 0x80000000) || bAlt))) {
  485. // only alt key pressed
  486. if (nMsg == WM_SYSKEYUP) {
  487. switch (m_nTrackingState) {
  488. case none:
  489. if (m_bIgnoreAlt == TRUE) {
  490. // LTRACE("    ignore ALT key upn");
  491. m_bIgnoreAlt = FALSE;
  492. break;
  493. }
  494. UpdateBar(button, GetNextOrPrevButton(0, FALSE));
  495. break;
  496. case button:
  497. UpdateBar();
  498. break;
  499. case buttonmouse:
  500. break; // do nothing
  501. }
  502. }
  503. return TRUE;
  504. }
  505. else if ((nMsg == WM_SYSKEYDOWN || nMsg == WM_KEYDOWN)) {
  506. if (m_nTrackingState == button) {
  507. if (m_dwStyle & CBRS_ORIENT_HORZ) { // if horizontal
  508. switch (vkey) {
  509. case VK_LEFT:
  510. case VK_RIGHT: {
  511. int nNewIndex  = GetNextOrPrevButton(m_nCurIndex, vkey == VK_LEFT);
  512. UpdateBar(button, nNewIndex);
  513. return TRUE;
  514.    }
  515. case VK_SPACE:
  516. case VK_UP:
  517. case VK_DOWN:
  518. TrackPopup(m_nCurIndex);
  519. return TRUE;
  520. case VK_ESCAPE:
  521. UpdateBar();
  522. return TRUE;
  523. }
  524. }
  525. else { // if vertical
  526. switch (vkey) {
  527. case VK_UP:
  528. case VK_DOWN:{
  529. int nNewIndex = GetNextOrPrevButton(m_nCurIndex, vkey == VK_UP);
  530. UpdateBar(button, nNewIndex);
  531. return TRUE;
  532.    }
  533. case VK_SPACE:
  534. case VK_RIGHT:
  535. case VK_LEFT:
  536. TrackPopup(m_nCurIndex);
  537. return TRUE;
  538. case VK_ESCAPE:
  539. UpdateBar();
  540. return TRUE;
  541. }
  542. }
  543. }
  544. // Alt + X pressed
  545. if ((bAlt || m_nTrackingState == button) && isalnum(vkey)) {
  546. int nIndex;
  547. if (MapAccessKey(vkey, nIndex) == TRUE) {
  548. UpdateBar();
  549. TrackPopup(nIndex);
  550. return TRUE; // eat it!
  551. }
  552. else if (m_nTrackingState==button && !bAlt) {
  553. // MessageBeep(0); // if you want
  554. return TRUE;
  555. }
  556. }
  557. if (m_nTrackingState > 0) { // unknown key
  558. if (m_nTrackingState != buttonmouse) { // if tracked with mouse, don't update bar
  559. UpdateBar();
  560. }
  561. }
  562. }
  563. }
  564. return FALSE; // pass along...
  565. }
  566. BOOL CMenuBar::MapAccessKey(TCHAR cAccessKey, int& nIndex)
  567. {
  568. for (int i = 0; i < GetItemCount(); ++i) {
  569. TCHAR cKey;
  570. if (m_arrItem[i]->GetAccessKey(cKey) == TRUE &&
  571. cKey == cAccessKey) {
  572. nIndex = i;
  573. return TRUE;
  574. }
  575. }
  576. return FALSE;
  577. }
  578. /////////////////////////////////////////////////////////////////////////////
  579. // CMenuBar layout
  580. // calculate only layout from m_bWrapped
  581. void CMenuBar::CalcFloatingLayout()
  582. {
  583. ASSERT_VALID(this);
  584. ASSERT(::IsWindow(m_hWnd));
  585. int xStart = CXGAP;
  586. if (!IsFloating()) {
  587. xStart += CXGRIPPER;
  588. }
  589. int xOffset = xStart;
  590. int yOffset = CYGAP;
  591. for (int i = 0; i < GetItemCount(); ++i) {
  592. CMenuItem* pItem = m_arrItem[i];
  593. if (pItem->IsValid()) {
  594. CPoint ptItem(xOffset, yOffset);
  595. pItem->Layout(ptItem, TRUE); // layout by itself!
  596. if (pItem->m_bWrapped == TRUE) {
  597. xOffset = xStart; // reset xOffset
  598. yOffset += pItem->m_sizeHorz.cy;
  599. }
  600. else
  601. xOffset += pItem->m_sizeHorz.cx;
  602. }
  603. }
  604. }
  605. // calulate ordinary layout and size without m_bWrapped 
  606. CSize CMenuBar::CalcLayout(DWORD dwMode, int nLength)
  607. {
  608. ASSERT_VALID(this);
  609. ASSERT(::IsWindow(m_hWnd));
  610. if (dwMode & LM_HORZDOCK)
  611. ASSERT(dwMode & LM_HORZ);
  612. CSize sizeResult(0, 0);
  613. if (!(dwMode & LM_HORZ))  { // if vertical
  614. int yOffset = CXGAP;
  615. if (!IsFloating())
  616. yOffset += CXGRIPPER;
  617. for (int i = 0; i < GetItemCount(); ++i) {
  618. CMenuItem* pItem = m_arrItem[i];
  619. if (pItem->IsValid()) {
  620. CPoint ptItem(CYGAPVERT, yOffset);
  621. pItem->Layout(ptItem, FALSE); // layout by itself
  622. yOffset += pItem->m_rcItem.Height();
  623. }
  624. }
  625. int cxBar = max(::GetSystemMetrics(SM_CXSMICON), cyMenuButton + (CYGAPVERT)*2);
  626. sizeResult =  CSize(cxBar, yOffset+CXGAP);
  627. }
  628. else { // if horizontal
  629. int xOffset = CXGAP;
  630. if (!IsFloating())
  631. xOffset += CXGRIPPER;
  632. for (int i = 0; i < GetItemCount(); ++i) {
  633. CMenuItem* pItem = m_arrItem[i];
  634. if (pItem->IsValid()) {
  635. CPoint ptItem(xOffset, CYGAP);
  636. pItem->Layout(ptItem, TRUE); // layout by itself
  637. xOffset += pItem->m_rcItem.Width();
  638. }
  639. }
  640. int cyBar = max(::GetSystemMetrics(SM_CYSMICON), cyMenuButton + CYGAP*2);
  641. sizeResult = CSize(xOffset+CXGAP, cyBar);
  642. }
  643. return sizeResult;
  644. //return CSize(400,100);
  645. }
  646. // in fact, it's never called
  647. CSize CMenuBar::CalcFixedLayout(BOOL bStretch, BOOL bHorz)
  648. {
  649. // LTRACE("CMenuBar::CalcFixedLayoutn");
  650. DWORD dwMode = bStretch ? LM_STRETCH : 0;
  651. dwMode |= bHorz ? LM_HORZ : 0;
  652. return CalcLayout(dwMode);
  653. }
  654. CSize CMenuBar::CalcDynamicLayout(int nLength, DWORD dwMode)
  655. {
  656. LTRACE("CMenuBar::CalcDynamicLayoutn");
  657. // Who can understand what "dwMode" means?
  658. // 
  659. // If you want it be pricisely same as DevStudio style,
  660. // I think you have to create a "CDockContext" derived class.
  661. // This is the reason why everyone think "CControlBar class" junk ? 
  662. ASSERT_VALID(this);
  663. ASSERT_VALID(m_pDockSite);
  664. ASSERT_VALID(m_pDockBar);
  665. if (m_hMenu == NULL) // if have no menu yet, just return
  666. return CSize(0, 0);
  667. if (IsFloating()) {
  668. CFrameWnd* pFrame = GetParentFrame();
  669. ASSERT_VALID(pFrame);
  670. CMenu* pSysMenu = pFrame->GetSystemMenu(FALSE);
  671. ASSERT_VALID(pSysMenu);
  672. pSysMenu->EnableMenuItem(SC_CLOSE, MF_BYCOMMAND | MF_DISABLED);
  673. }
  674. if (dwMode & LM_HORZ) { // horizontal
  675. // LTRACE("    horizontaln");
  676. if (dwMode & LM_HORZDOCK) {
  677. if (IsFloating() || (m_dwStyle & CBRS_ORIENT_VERT)) { // if Floating->Docking, return min size
  678. // LTRACE("    return min sizen");
  679. return CalcLayout(dwMode);
  680. //return CalcSize(GetItemCount()); //Modify by xhs
  681. }
  682. else {
  683. if (m_pDockContext->m_pDC) { // now dragging
  684. // return DockBar size
  685. //LTRACE("    now dragging, so calc with DockBarn");
  686. CSize size = CalcSize(GetItemCount());//CalcLayout(dwMode);
  687. CRect rcFrame;
  688. m_pDockBar->GetWindowRect(rcFrame);
  689. CRect rcBar;
  690. GetWindowRect(rcBar);
  691. rcBar.right = rcFrame.right;
  692. return CSize(rcBar.Width() + cxBorder2, size.cy);
  693. //return CalcSize(GetItemCount()); //Modify by xhs
  694. }
  695. else {
  696. //LTRACE("    no draggin calc bigger sizen");
  697. CRect rcFrame;
  698. m_pDockSite->GetWindowRect(rcFrame);
  699. SizeMenuBar(GetItemCount(), rcFrame.Width() - cxBorder2*2, FALSE);
  700. CalcFloatingLayout();
  701. CSize size1 = CalcSize(GetItemCount());
  702. return CSize(rcFrame.Width(), size1.cy);
  703.     //return CalcSize(GetItemCount()); //Modify by xhs
  704. }
  705. }
  706. }
  707. else if (dwMode & LM_MRUWIDTH) { // floating size
  708. //LTRACE("    return floating sizen");
  709. SizeMenuBar(GetItemCount(), m_nMRUWidth, FALSE); // load floating Bar Width! 
  710. CalcFloatingLayout();
  711. return CalcSize(GetItemCount());
  712. }
  713. else if (dwMode & LM_COMMIT) {
  714. //LTRACE("    commit, just calc: %dn", nLength);
  715. m_nMRUWidth = nLength; // save floating Bar Width!!! (used when SaveBarState)
  716. CalcFloatingLayout();
  717. return CSize(0, 0); // MFC does'nt use this Size
  718. }
  719. else if (dwMode & LM_LENGTHY) {
  720. //LTRACE("    nLength is height : %dn", nLength);
  721. SizeMenuBar(GetItemCount(), nLength, TRUE);
  722. return CalcSize(GetItemCount());
  723. }
  724. else {
  725. //LTRACE("    nLength is width  : %dn", nLength);
  726. SizeMenuBar(GetItemCount(), nLength, FALSE);
  727. return CalcSize(GetItemCount());
  728. }
  729. ASSERT(TRUE);
  730. }
  731. else { // vertical
  732. InvalidateRect(NULL); // force to repaint!!!
  733. //LTRACE("    verticaln");
  734. if (IsFloating() || (m_dwStyle & CBRS_ORIENT_HORZ)) { // if Floating->Docking, return min size
  735. //LTRACE("    return min sizen");
  736. return CalcLayout(dwMode);
  737. }
  738. else { // return large size
  739. if (m_pDockContext->m_pDC) { // CDockContext::m_bDragging is not helpful :(
  740. //LTRACE("    now dragging, so calc with DockBarn");
  741. CSize size = CalcLayout(dwMode);
  742. CRect rcFrame;
  743. m_pDockBar->GetWindowRect(rcFrame);
  744. CRect rcBar;
  745. GetWindowRect(rcBar);
  746. rcBar.bottom = rcFrame.bottom;
  747. return CSize(size.cx, rcBar.Height());
  748. }
  749. else {
  750. //LTRACE("    no dragging, return biggest sizen");
  751. CSize size = CalcLayout(dwMode);
  752. CRect rcFrame;
  753. m_pDockSite->GetWindowRect(rcFrame);
  754. CRect rcBar;
  755. GetWindowRect(rcBar);
  756. rcBar.bottom = rcFrame.bottom;
  757. return CSize(size.cx, rcFrame.Height());
  758. }
  759. }
  760. }
  761. ASSERT(TRUE); // never come here
  762. return CalcLayout(dwMode, nLength);
  763. }
  764. void CMenuBar::DrawGripper(CDC* pDC)
  765. {
  766. if( (m_dwStyle & CBRS_FLOATING) || m_dwDockStyle == 0 )
  767. return;
  768. CRect rcGrip;
  769. GetClientRect(&rcGrip);
  770. if(m_dwStyle & CBRS_ORIENT_HORZ) {
  771. // gripper at left
  772. //rcGrip.DeflateRect(4, 3);
  773. rcGrip.right = rcGrip.left + 3;
  774. //pDC->DrawEdge(rcGrip, BDR_RAISEDINNER, BF_RECT);
  775. rcGrip.OffsetRect(4, 0);
  776.         pDC->DrawEdge(rcGrip, BDR_RAISEDINNER, BF_RECT);
  777. }
  778. else {
  779. // gripper at top
  780. rcGrip.DeflateRect(3, 4);
  781. rcGrip.bottom = rcGrip.top + 3;
  782. pDC->DrawEdge(rcGrip, BDR_RAISEDINNER, BF_RECT);
  783. //rcGrip.OffsetRect(0, 4);
  784. //pDC->DrawEdge(rcGrip, BDR_RAISEDINNER, BF_RECT);
  785. }
  786. }
  787. #define CX_BORDER   1
  788. #define CY_BORDER   1
  789. void CMenuBar::DrawBorder(CDC* pDC)
  790. {
  791. if( (m_dwStyle & CBRS_FLOATING) || m_dwDockStyle == 0 )
  792. return;
  793. CRect rect;
  794. GetClientRect(rect);
  795. DWORD dwStyle = m_dwStyle;
  796. if (!(dwStyle & CBRS_BORDER_ANY))
  797. return;
  798. CRect rect3 = rect;
  799. if (m_dwStyle & CBRS_ORIENT_HORZ) {
  800. rect3.left += cxBorder2;//rect.DeflateRect(2, 0);
  801. pDC->DrawEdge(rect3, BDR_RAISEDINNER ,BF_LEFT);
  802. }
  803. else {
  804. rect3.top += cyBorder2;//rect.DeflateRect(0, 2);
  805. pDC->DrawEdge(rect3,BDR_RAISEDINNER ,  BF_TOP);
  806. }
  807. // prepare for dark lines
  808. ASSERT(rect.top == 0 && rect.left == 0);
  809. CRect rect1, rect2;
  810. rect1 = rect;
  811. rect2 = rect;
  812. COLORREF clr = ::GetSysColor(COLOR_BTNSHADOW);//afxData.bWin4 ? afxData.clrBtnShadow : afxData.clrWindowFrame;
  813. // draw dark line one pixel back/up
  814. if (dwStyle & CBRS_BORDER_3D)
  815. {
  816. rect1.right -= CX_BORDER;
  817. rect1.bottom -= CY_BORDER;
  818. }
  819. if (dwStyle & CBRS_BORDER_TOP)
  820. rect2.top += CY_BORDER;//cyBorder2;
  821. if (dwStyle & CBRS_BORDER_BOTTOM)
  822. rect2.bottom -= CY_BORDER;
  823. if (dwStyle & CBRS_BORDER_LEFT)
  824. rect2.left += CX_BORDER;
  825. if (dwStyle & CBRS_BORDER_RIGHT)
  826. rect2.right -= CX_BORDER;
  827. if (dwStyle & CBRS_BORDER_3D)
  828. {
  829. // draw left and top
  830. if (dwStyle & CBRS_BORDER_LEFT)
  831. pDC->DrawEdge(rect2, BDR_RAISEDINNER, BF_LEFT);//pDC->FillSolidRect(1, rect2.top, CX_BORDER, rect2.Height(), clr);
  832. if (dwStyle & CBRS_BORDER_TOP)
  833. pDC->DrawEdge(rect2, BDR_RAISEDINNER, BF_TOP);//pDC->FillSolidRect(0, 1, rect.right, CY_BORDER, clr);
  834. // draw right and bottom
  835. if (dwStyle & CBRS_BORDER_RIGHT)
  836. pDC->DrawEdge(rect2, BDR_RAISEDINNER, BF_RIGHT);//pDC->FillSolidRect(rect.right, rect2.top, -CX_BORDER, rect2.Height(), clr);
  837. if (dwStyle & CBRS_BORDER_BOTTOM)
  838. pDC->DrawEdge(rect2, BDR_RAISEDINNER, BF_BOTTOM);//pDC->FillSolidRect(0, rect.bottom, rect.right, -CY_BORDER, clr);
  839. }
  840. }
  841. /////////////////////////////////////////////////////////////////////////////
  842. // CMenuBarFrameHook implementation
  843. CMenuBarFrameHook::CMenuBarFrameHook()
  844. {
  845. m_pMenuBar = NULL;
  846. }
  847. BOOL CMenuBarFrameHook::Install(CMenuBar* pMenuBar, HWND hWndToHook)
  848. {
  849. ASSERT_VALID(pMenuBar);
  850. ASSERT(m_pMenuBar == NULL);
  851. m_pMenuBar = pMenuBar;
  852. return HookWindow(hWndToHook);//CWnd::FromHandlePermanent(hWndToHook));
  853. }
  854. CMenuBarFrameHook::~CMenuBarFrameHook()
  855. {
  856. }
  857. LRESULT CMenuBarFrameHook::WindowProc(UINT nMsg, WPARAM wParam, LPARAM lParam)
  858. {
  859. ASSERT_VALID(m_pMenuBar);
  860. switch (nMsg) {
  861. case WM_MENUSELECT:
  862. m_pMenuBar->OnMenuSelect((HMENU)lParam, (UINT)LOWORD(wParam));
  863. break;
  864. // The following messages are trapped for the MDI client window
  865. case WM_INITMENUPOPUP:
  866. LTRACE("CMenuBar::WM_INITMENUPOPUPn");
  867. if (!HIWORD(lParam) && (HMENU)wParam == m_pMenuBar->m_hWindowMenu)
  868. m_pMenuBar->OnInitMenuPopup();
  869. break;
  870. case WM_MDISETMENU: // only sent to MDI client window
  871. // Setting new frame/window menu: bypass MDI. wParam is new menu.
  872. if (wParam) {
  873. LTRACE("CMenuBar::WM_MDISETMENU 0x%04xn", wParam);
  874. // HMENU hNewMenu = (HMENU)wParam;
  875. m_pMenuBar->OnSetMenu((HMENU)wParam, (HMENU)lParam);
  876. }
  877. return 0;
  878. case WM_MDIREFRESHMENU: // only sent to MDI client window
  879. // Normally, would call DrawMenuBar, but I have the menu, so eat it.
  880. // LTRACE("CMenuBar::WM_MDIREFRESHMENUn");
  881. return 0;
  882. case WM_PAINT:
  883. // After changing the MDI maximized state, the client window gets a
  884. // paint message. This is the most convenient place to find out; there
  885. // is no WM_MDIMAXIMIZED message.
  886. if (/*m_pWndHooked->*/m_hWnd == m_pMenuBar->m_hWndMDIClient)
  887. m_pMenuBar->OnPaintMDIClient();//CheckMinMaxState();
  888. break;
  889. }
  890. return CSubclassWnd::WindowProc(nMsg, wParam, lParam);
  891. }
  892. void CMenuBar::OnLButtonUp(UINT nFlags, CPoint point) 
  893. {
  894. //LTRACE("CMenuBar::OnLButtonUpn");
  895. // TODO: 
  896. ASSERT(m_pMenuControl);
  897. if (m_pMenuControl->OnMouseMsg(WM_LBUTTONUP, nFlags, point)) {
  898. CControlBar::OnLButtonUp(nFlags, point);
  899. return;
  900. }
  901. int nIndex = HitTestOnTrack(point);
  902. /*
  903. if (IsValidIndex(nIndex) && m_bDown == TRUE) {
  904. HMENU hSubMenu = ::GetSubMenu(m_hMenu, nIndex);
  905. if (hSubMenu == NULL) {
  906. UINT nID = ::GetMenuItemID(m_hMenu, nIndex);
  907. ASSERT(nID != -1);
  908. GetOwner()->SendMessage(WM_COMMAND, (WPARAM)nID, (LPARAM)GetSafeHwnd());
  909. UpdateBar();
  910. }
  911. }
  912. */
  913. CControlBar::OnLButtonUp(nFlags, point);
  914. }
  915. void CMenuBar::DoPaint(CDC* pDC)
  916. {
  917. //LTRACE("CMenuBar::DoPaintn");
  918. CRect rect;
  919. GetClientRect(rect);
  920. // draw buttons
  921. for (int i = 0; i < m_arrItem.GetSize(); ++i) {
  922. CMenuItem* pItem = m_arrItem[i];
  923. if (pItem->IsValid())
  924. m_arrItem[i]->Update(pDC);
  925. }
  926. // draw decorations
  927. DrawGripper(pDC);
  928. DrawBorder(pDC);
  929. // draw captions
  930. if (m_pMenuControl) {
  931. CRect rcDockBar;
  932. m_pDockBar->GetClientRect(rcDockBar);
  933. if (m_dwStyle & CBRS_ORIENT_HORZ) {
  934. m_pMenuControl->DelayLayoutAndDraw(pDC, CSize(rcDockBar.Width() + cxBorder2, rect.Height()));
  935. }
  936. else {
  937. m_pMenuControl->DelayLayoutAndDraw(pDC, CSize(rect.Width(), rcDockBar.Height()));
  938. }
  939. }
  940. }
  941. HMENU CMenuBar::GetMyMenu()
  942. {
  943. return m_hMenu;
  944. }
  945. void CMenuBar::_KillTimer()
  946. {
  947. if (m_nIDEvent) {
  948. KillTimer(m_nIDEvent);
  949. m_nIDEvent = NULL;
  950. }
  951. }
  952. int getPrevValidIndex(int nIndex)
  953. {
  954. --nIndex;
  955. return nIndex;
  956. }
  957. // set only m_bWrapped by nWidth
  958. int CMenuBar::WrapMenuBar(int nCount, int nWidth)
  959. {
  960. // LTRACE("CMenuBar::WrapMenuBarn");
  961. int nResult = 0;
  962. int xStart = CXGAP;
  963. if (!IsFloating() && !m_pDockContext->m_pDC) // if not floating and ****not dragging!!!****
  964. xStart += CXGRIPPER;
  965. int x = xStart;
  966. for (int i = 0; i < nCount; ++i) {
  967. CMenuItem* pItem = m_arrItem[i];
  968. if (pItem->IsValid()) {
  969. if (i+1 == nCount)
  970. return ++nResult;
  971. if (x + pItem->m_sizeHorz.cx + CXGAP> nWidth) {// itself is over
  972. if (pItem->CanWrap()) {
  973. pItem->m_bWrapped = TRUE;
  974. ++nResult;
  975. x = xStart;
  976. }
  977. }
  978. else if (x + pItem->m_sizeHorz.cx + m_arrItem[i+1]->m_sizeHorz.cx + CXGAP > nWidth) {
  979. if (pItem->CanWrap()) {
  980. pItem->m_bWrapped = TRUE;
  981. ++nResult;
  982. x = xStart;
  983. }
  984. }
  985. else {
  986. pItem->m_bWrapped = FALSE;
  987. x += pItem->m_sizeHorz.cx;
  988. }
  989. }
  990. }
  991. /* //another algorithm
  992. int dx = pItem->m_sizeHorz.cx;
  993. if (dx + CXGAP > nWidth) { // bigger than nWidth
  994. if (pItem->CanWrap()) {
  995. pItem->m_bWrapped = TRUE;
  996. // if (i != nCount - 1)
  997. ++nResult;
  998. }
  999. }
  1000. else if (dx + x + CXGAP > nWidth) {
  1001. if (i > 0 && m_arrItem[i-1]->CanWrap()) {
  1002. // LTRACE("index %d is wrapn", i-1);
  1003. m_arrItem[i-1]->m_bWrapped = TRUE;
  1004. pItem->m_bWrapped = FALSE;
  1005. x = xStart;
  1006. // if (i != nCount - 1)///////////////////////////
  1007. ++nResult;
  1008. }
  1009. }
  1010. else {
  1011. pItem->m_bWrapped = FALSE;
  1012. }
  1013. x += dx;
  1014. }
  1015. }
  1016. */
  1017. return nResult + 1;
  1018. }
  1019. // calc only size, by using m_bWrapped
  1020. CSize CMenuBar::CalcSize(int nCount)
  1021. {
  1022. ASSERT(nCount > 0);
  1023. CPoint cur(CXGAP, CYGAP);
  1024. CSize sizeResult(0, 0);
  1025. int nWrap = 0;
  1026. for (int i = 0; i < nCount; ++i) {
  1027. CMenuItem* pItem = m_arrItem[i];
  1028. if (pItem->IsValid()) {
  1029. sizeResult.cx = max(cur.x + pItem->m_sizeHorz.cx, sizeResult.cx);
  1030. sizeResult.cy = max(cur.y + pItem->m_sizeHorz.cy, sizeResult.cy);
  1031. cur.x += pItem->m_sizeHorz.cx;
  1032. if (pItem->m_bWrapped == TRUE) {
  1033. LTRACE("    nIndex:%d is wrappedn", i);
  1034. cur.x = CXGAP; // reset x pos
  1035. cur.y += pItem->m_sizeHorz.cy;
  1036. ++nWrap;
  1037. }
  1038. }
  1039. }
  1040. //sizeResult.cy += CYGAP;
  1041. //sizeResult.cx += CXGAP;
  1042. // Modify by xhs , and the width of menubar will be shorter
  1043. sizeResult.cy += (CYGAP-4);
  1044. sizeResult.cx += (CXGAP+2);  
  1045. return sizeResult;
  1046. }
  1047. void CMenuBar::SizeMenuBar(int nCount, int nLength, BOOL bVert)
  1048. {
  1049. //LTRACE("CMenuBar::SizeMenuBarn");
  1050. ASSERT(nCount > 0);
  1051. if (!bVert) { // nLength is horizontal length
  1052. if (IsFloating()) { // half size wrapping
  1053. CSize sizeMax, sizeMin, sizeMid;
  1054. // Wrap MenuBar vertically
  1055. WrapMenuBar(nCount, 0);
  1056. sizeMin = CalcSize(nCount);
  1057. // Wrap MenuBar horizontally
  1058. WrapMenuBar(nCount, 32767);
  1059. sizeMax = CalcSize(nCount);
  1060. // we can never know this algorithm :), see CToolBar implementation
  1061. while (sizeMin.cx < sizeMax.cx) {
  1062. // LTRACE("looping sizeMin.cx:%d < sizeMax.cx:%dn", sizeMin.cx, sizeMax.cx);
  1063. sizeMid.cx = (sizeMin.cx + sizeMax.cx) / 2;
  1064. WrapMenuBar(nCount, sizeMid.cx);
  1065. sizeMid = CalcSize(nCount);
  1066. if (sizeMid.cx == sizeMax.cx) { // if you forget, it loops forever!
  1067. return;
  1068. }
  1069. // LTRACE("    sizeMid : %d %dn", sizeMid.cx, sizeMid.cy);
  1070. if (nLength >= sizeMax.cx) {
  1071. // LTRACE("    nLength:%d >= sizeMax.cx:%dn", nLength, sizeMax.cx);
  1072. if (sizeMin == sizeMid) {
  1073. WrapMenuBar(nCount, sizeMax.cx);
  1074. // LTRACE("out SizeMenuBarn");
  1075. return;
  1076. }
  1077. sizeMin = sizeMid;
  1078. }
  1079. else if (nLength < sizeMax.cx) {
  1080. // LTRACE("    nLength:%d < sizeMax.cx:%dn", nLength, sizeMax.cx);
  1081. sizeMax = sizeMid;
  1082. }
  1083. else {
  1084. // LTRACE("out SizeMenuBarn");
  1085. return;
  1086. }
  1087. }
  1088. }
  1089. else { // each one wrapping
  1090. LTRACE("    just each one wrappingn");
  1091. WrapMenuBar(nCount, nLength);
  1092. }
  1093. }
  1094. else { // nLength is vertical length
  1095. CSize sizeMax, sizeMin, sizeMid;
  1096. // Wrap MenuBar vertically
  1097. WrapMenuBar(nCount, 0);
  1098. sizeMin = CalcSize(nCount);
  1099. // Wrap MenuBar horizontally
  1100. WrapMenuBar(nCount, 32767);
  1101. sizeMax = CalcSize(nCount);
  1102. while (sizeMin.cx < sizeMax.cx) {
  1103. sizeMid.cx = (sizeMin.cx + sizeMax.cx) / 2;
  1104. WrapMenuBar(nCount, sizeMid.cx);
  1105. sizeMid = CalcSize(nCount);
  1106. if (sizeMid.cx == sizeMax.cx) {
  1107. return;
  1108. }
  1109. if (nLength < sizeMid.cy) {
  1110. if (sizeMin == sizeMid) {
  1111. WrapMenuBar(nCount, sizeMax.cx);
  1112. //LTRACE("out SizeMenuBarn");
  1113. return;
  1114. }
  1115. sizeMin = sizeMid;
  1116. }
  1117. else if (nLength > sizeMid.cy)
  1118. sizeMax = sizeMid;
  1119. else {
  1120. //LTRACE("out SizeMenuBarn");
  1121. return;
  1122. }
  1123. }
  1124. }
  1125. //LTRACE("out SizeMenuBarn");
  1126. }
  1127. void CMenuBar::DeleteItems()
  1128. {
  1129. for(int i = 0; i < m_arrItem.GetSize(); ++i) {
  1130. CMenuItem* pItem = m_arrItem[i];
  1131. delete pItem;
  1132. }
  1133. m_arrItem.RemoveAll();
  1134. m_pMenuIcon = NULL;
  1135. m_pMenuControl = NULL;
  1136. }
  1137. void CMenuBar::OnDestroy() 
  1138. {
  1139. CControlBar::OnDestroy();
  1140. _KillTimer();
  1141. DeleteItems();
  1142. }
  1143. int CMenuBar::GetNextOrPrevButton(int nIndex, BOOL bPrev)
  1144. {
  1145. int nCount = GetItemCount();
  1146. if (bPrev) { // <-
  1147. --nIndex;
  1148. if (nIndex < 0)
  1149. nIndex = nCount - 1;
  1150. }
  1151. else { // ->
  1152. ++nIndex;
  1153. if (nIndex >= nCount)
  1154. nIndex = 0;
  1155. }
  1156. if (!m_arrItem[nIndex]->CanTrack() || !m_arrItem[nIndex]->IsValid()) {
  1157. return GetNextOrPrevButton(nIndex, bPrev);
  1158. }
  1159. return nIndex;
  1160. }
  1161. void CMenuBar::AddIcon(HICON hIcon)
  1162. {
  1163. // ASSERT(m_bIcon == FALSE);
  1164. // m_bIcon = TRUE;
  1165. }
  1166. CMenuControl::CMenuControl(CControlBar* pBar)
  1167. {
  1168. m_bValid = FALSE;
  1169. m_pBar = pBar;
  1170. m_bDown = FALSE;
  1171. m_nTracking = -1;
  1172. int cxCaption = cyMenuButton - CYGAP + 1;
  1173. m_sizeHorz = CSize(cxCaption*3 + CXGAP/2, cyMenuButton);
  1174. }
  1175. CMenuControl::~CMenuControl()
  1176. {
  1177. }
  1178. void CMenuControl::Update(CDC* pDC)
  1179. {
  1180. // do nothing
  1181. }
  1182. void CMenuControl::Layout(CPoint point, BOOL bHorz)
  1183. {
  1184. LTRACE("CMenuControl::Layout bHorz:%dn", bHorz);
  1185. m_bHorz = bHorz;
  1186. // just layout easily
  1187. if (bHorz) {
  1188. m_rcItem = CRect(point, m_sizeHorz);
  1189. }
  1190. else {
  1191. m_rcItem = CRect(point, CSize(m_sizeHorz.cy, m_sizeHorz.cx));
  1192. }
  1193. }
  1194. void CMenuControl::DelayLayoutAndDraw(CDC* pDC, CSize sizeBar)
  1195. {
  1196. // if (!IsValid())
  1197. // return;
  1198. // layout
  1199. if (m_bHorz) {
  1200. int cxCaption = cyMenuButton - CYGAP + 1;
  1201. int cyCaption = cxCaption - 1;
  1202. CRect rcCaption;
  1203. rcCaption.right = sizeBar.cx;
  1204. rcCaption.bottom = sizeBar.cy - CYGAP;
  1205. rcCaption.left = rcCaption.right - cxCaption;
  1206. rcCaption.top = rcCaption.bottom - cyCaption;
  1207. m_arrCaption[0] = rcCaption;
  1208. rcCaption -= CPoint(cxCaption+CXGAP/2, 0);
  1209. m_arrCaption[1] = rcCaption;
  1210. rcCaption -= CPoint(cxCaption, 0);
  1211. m_arrCaption[2] = rcCaption;
  1212. m_rcItem = CRect(m_arrCaption[2].left, m_arrCaption[2].top,
  1213. m_arrCaption[0].right, m_arrCaption[0].bottom);
  1214. }
  1215. else {
  1216. int cxCaption = cyMenuButton - CYGAPVERT - 1;
  1217. int cyCaption = cxCaption - 1;
  1218. CRect rcCaption;
  1219. rcCaption.left = CYGAPVERT;
  1220. rcCaption.bottom = sizeBar.cy;
  1221. rcCaption.right = rcCaption.left + cxCaption;
  1222. rcCaption.top = rcCaption.bottom - cyCaption;
  1223. m_arrCaption[0] = rcCaption;
  1224. rcCaption -= CPoint(0, cyCaption+CXGAP/2);
  1225. m_arrCaption[1] = rcCaption;
  1226. rcCaption -= CPoint(0, cyCaption);
  1227. m_arrCaption[2] = rcCaption;
  1228. m_rcItem = CRect(m_arrCaption[2].left, m_arrCaption[2].top,
  1229. m_arrCaption[0].right, m_arrCaption[0].bottom);
  1230. }
  1231. if (!IsValid())
  1232. return;
  1233. // draw frame controls
  1234. for (int i = 0; i < 3; ++i) {
  1235. DrawControl(pDC, i, FALSE);
  1236. }
  1237. // pDC->DrawFrameControl(m_arrCaption[0], DFC_CAPTION, DFCS_CAPTIONCLOSE);
  1238. // pDC->DrawFrameControl(m_arrCaption[1], DFC_CAPTION, DFCS_CAPTIONRESTORE);
  1239. // pDC->DrawFrameControl(m_arrCaption[2], DFC_CAPTION, DFCS_CAPTIONMIN);
  1240. }
  1241. // pasted from CDockContext
  1242. void CMenuBarDockContext::StartDrag(CPoint pt)
  1243. {
  1244. ASSERT_VALID(m_pBar);
  1245. m_bDragging = TRUE;
  1246. InitLoop();
  1247. if (m_pBar->m_dwStyle & CBRS_SIZE_DYNAMIC)
  1248. {
  1249. // get TRUE bar size (including borders)
  1250. CRect rect;
  1251. m_pBar->GetWindowRect(rect);
  1252. m_ptLast = pt;
  1253. CSize sizeHorz = m_pBar->CalcDynamicLayout(0, LM_HORZ | LM_HORZDOCK);
  1254. CSize sizeVert = m_pBar->CalcDynamicLayout(0, LM_VERTDOCK);
  1255. CSize sizeFloat = m_pBar->CalcDynamicLayout(0, LM_HORZ | LM_MRUWIDTH);
  1256. m_rectDragHorz = CRect(rect.TopLeft(), sizeHorz);
  1257. m_rectDragVert = CRect(rect.TopLeft(), sizeVert);
  1258. // calculate frame dragging rectangle
  1259. m_rectFrameDragHorz = CRect(rect.TopLeft(), sizeFloat);
  1260. m_rectFrameDragVert = CRect(rect.TopLeft(), sizeFloat);
  1261. #ifdef _MAC
  1262. CMiniFrameWnd::CalcBorders(&m_rectFrameDragHorz,
  1263. WS_THICKFRAME | WS_CAPTION, WS_EX_FORCESIZEBOX);
  1264. CMiniFrameWnd::CalcBorders(&m_rectFrameDragVert,
  1265. WS_THICKFRAME | WS_CAPTION, WS_EX_FORCESIZEBOX);
  1266. #else
  1267. CMiniFrameWnd::CalcBorders(&m_rectFrameDragHorz);
  1268. CMiniFrameWnd::CalcBorders(&m_rectFrameDragVert);
  1269. #endif
  1270. m_rectFrameDragHorz.InflateRect(-cxBorder2, -cyBorder2);
  1271. m_rectFrameDragVert.InflateRect(-cxBorder2, -cyBorder2);
  1272. }
  1273. else if (m_pBar->m_dwStyle & CBRS_SIZE_FIXED)
  1274. {
  1275. // get TRUE bar size (including borders)
  1276. CRect rect;
  1277. m_pBar->GetWindowRect(rect);
  1278. m_ptLast = pt;
  1279. CSize sizeHorz = m_pBar->CalcDynamicLayout(-1, LM_HORZ | LM_HORZDOCK);
  1280. CSize sizeVert = m_pBar->CalcDynamicLayout(-1, LM_VERTDOCK);
  1281. // calculate frame dragging rectangle
  1282. m_rectFrameDragHorz = m_rectDragHorz = CRect(rect.TopLeft(), sizeHorz);
  1283. m_rectFrameDragVert = m_rectDragVert = CRect(rect.TopLeft(), sizeVert);
  1284. CMiniFrameWnd::CalcBorders(&m_rectFrameDragHorz);
  1285. CMiniFrameWnd::CalcBorders(&m_rectFrameDragVert);
  1286. m_rectFrameDragHorz.InflateRect(-cxBorder2, -cyBorder2);
  1287. m_rectFrameDragVert.InflateRect(-cxBorder2, -cyBorder2);
  1288. }
  1289. else
  1290. {
  1291. // get TRUE bar size (including borders)
  1292. CRect rect;
  1293. m_pBar->GetWindowRect(rect);
  1294. m_ptLast = pt;
  1295. BOOL bHorz = HORZF(m_dwStyle);
  1296. DWORD dwMode = !bHorz ? (LM_HORZ | LM_HORZDOCK) : LM_VERTDOCK;
  1297. CSize size = m_pBar->CalcDynamicLayout(-1, dwMode);
  1298. // calculate inverted dragging rect
  1299. if (bHorz)
  1300. {
  1301. m_rectDragHorz = rect;
  1302. m_rectDragVert = CRect(CPoint(pt.x - rect.Height()/2, rect.top), size);
  1303. }
  1304. else // vertical orientation
  1305. {
  1306. m_rectDragVert = rect;
  1307. m_rectDragHorz = CRect(CPoint(rect.left, pt.y - rect.Width()/2), size);
  1308. }
  1309. // calculate frame dragging rectangle
  1310. m_rectFrameDragHorz = m_rectDragHorz;
  1311. m_rectFrameDragVert = m_rectDragVert;
  1312. CMiniFrameWnd::CalcBorders(&m_rectFrameDragHorz);
  1313. CMiniFrameWnd::CalcBorders(&m_rectFrameDragVert);
  1314. m_rectFrameDragHorz.InflateRect(-cxBorder2, -cyBorder2);
  1315. m_rectFrameDragVert.InflateRect(-cxBorder2, -cyBorder2);
  1316. }
  1317. // adjust rectangles so that point is inside
  1318. AdjustRectangle(m_rectDragHorz, pt);
  1319. AdjustRectangle(m_rectDragVert, pt);
  1320. AdjustRectangle(m_rectFrameDragHorz, pt);
  1321. AdjustRectangle(m_rectFrameDragVert, pt);
  1322. // initialize tracking state and enter tracking loop
  1323. m_dwOverDockStyle = CanDock();
  1324. Move(pt);   // call it here to handle special keys
  1325. _Track();
  1326. }
  1327. BOOL CMenuBarDockContext::_Track()
  1328. {
  1329. // don't handle if capture already set
  1330. if (::GetCapture() != NULL)
  1331. return FALSE;
  1332. // set capture to the window which received this message
  1333. m_pBar->SetCapture();
  1334. ASSERT(m_pBar == CWnd::GetCapture());
  1335. #ifndef _MAC
  1336. // get messages until capture lost or cancelled/accepted
  1337. while (CWnd::GetCapture() == m_pBar)
  1338. {
  1339. MSG msg;
  1340. if (!::GetMessage(&msg, NULL, 0, 0))
  1341. {
  1342. AfxPostQuitMessage(msg.wParam);
  1343. break;
  1344. }
  1345. switch (msg.message)
  1346. {
  1347. case WM_LBUTTONUP:
  1348. if (m_bDragging)
  1349. _EndDrag();
  1350. else
  1351. EndResize();
  1352. return TRUE;
  1353. case WM_MOUSEMOVE:
  1354. if (m_bDragging)
  1355. Move(msg.pt);
  1356. else
  1357. Stretch(msg.pt);
  1358. break;
  1359. case WM_KEYUP:
  1360. if (m_bDragging)
  1361. OnKey((int)msg.wParam, FALSE);
  1362. break;
  1363. case WM_KEYDOWN:
  1364. if (m_bDragging)
  1365. OnKey((int)msg.wParam, TRUE);
  1366. if (msg.wParam == VK_ESCAPE)
  1367. {
  1368. CancelLoop();
  1369. return FALSE;
  1370. }
  1371. break;
  1372. case WM_RBUTTONDOWN:
  1373. CancelLoop();
  1374. return FALSE;
  1375. // just dispatch rest of the messages
  1376. default:
  1377. DispatchMessage(&msg);
  1378. break;
  1379. }
  1380. }
  1381. #else
  1382. Point   ptCur = {0};
  1383. // get messages until capture lost or cancelled/accepted
  1384. while (CWnd::GetCapture() == m_pBar)
  1385. {
  1386. EventRecord     er;
  1387. if (OSEventAvail(everyEvent, &er))
  1388. {
  1389. GetNextEvent(everyEvent, &er);
  1390. switch (er.what)
  1391. {
  1392. case mouseUp:
  1393. if (m_bDragging)
  1394. EndDrag();
  1395. else
  1396. EndResize();
  1397. return TRUE;
  1398. case keyDown:
  1399. case keyUp:
  1400. case autoKey:
  1401. case app2Evt:
  1402. {
  1403. MSG     msg;
  1404. if (WrapEvent(&er, &msg, PM_REMOVE))
  1405. {
  1406. if (m_bDragging)
  1407. OnKey((int)msg.wParam, msg.message == WM_KEYDOWN);
  1408. if (msg.message == WM_KEYUP && msg.wParam == VK_ESCAPE)
  1409. {
  1410. CancelLoop();
  1411. return FALSE;
  1412. }
  1413. }
  1414. break;
  1415. }
  1416. default:
  1417. break;
  1418. }
  1419. }
  1420. else
  1421. {
  1422. if (!EqualPt(er.where, ptCur))
  1423. {
  1424. POINT pt = {er.where.h, er.where.v};
  1425. if (m_bDragging)
  1426. Move(pt);
  1427. else
  1428. Stretch(pt);
  1429. }
  1430. }
  1431. }
  1432. #endif
  1433. CancelLoop();
  1434. return FALSE;
  1435. }
  1436. void CMenuBarDockContext::_EndDrag()
  1437. {
  1438. CancelLoop();
  1439. if (m_dwOverDockStyle != 0)
  1440. {
  1441. CDockBar* pDockBar = GetDockBar(m_dwOverDockStyle);
  1442. ASSERT(pDockBar != NULL);
  1443. CRect rect = (m_dwOverDockStyle & CBRS_ORIENT_VERT) ?
  1444. m_rectDragVert : m_rectDragHorz;
  1445. UINT uID = _AfxGetDlgCtrlID(pDockBar->m_hWnd);
  1446. if (uID >= AFX_IDW_DOCKBAR_TOP &&
  1447. uID <= AFX_IDW_DOCKBAR_BOTTOM)
  1448. {
  1449. m_uMRUDockID = uID;
  1450. m_rectMRUDockPos = rect;
  1451. pDockBar->ScreenToClient(&m_rectMRUDockPos);
  1452. }
  1453. // dock it at the specified position, RecalcLayout will snap
  1454. // insisting own line trick!
  1455. CRect rcDockBar;
  1456. pDockBar->GetWindowRect(rcDockBar);
  1457. if (m_dwOverDockStyle & CBRS_ORIENT_VERT) {
  1458. rect.top = rcDockBar.top - 1;
  1459. }
  1460. else {
  1461. rect.left = rcDockBar.left - 10;
  1462. }
  1463. m_pDockSite->DockControlBar(m_pBar, pDockBar, &rect);
  1464. m_pDockSite->RecalcLayout();
  1465. }
  1466. else if ((m_dwStyle & CBRS_SIZE_DYNAMIC) || (HORZF(m_dwStyle) && !m_bFlip) ||
  1467. (VERTF(m_dwStyle) && m_bFlip))
  1468. {
  1469. m_dwMRUFloatStyle = CBRS_ALIGN_TOP | (m_dwDockStyle & CBRS_FLOAT_MULTI);
  1470. m_ptMRUFloatPos = m_rectFrameDragHorz.TopLeft();
  1471. m_pDockSite->FloatControlBar(m_pBar, m_ptMRUFloatPos, m_dwMRUFloatStyle);
  1472. }
  1473. else // vertical float
  1474. {
  1475. m_dwMRUFloatStyle = CBRS_ALIGN_LEFT | (m_dwDockStyle & CBRS_FLOAT_MULTI);
  1476. m_ptMRUFloatPos = m_rectFrameDragVert.TopLeft();
  1477. m_pDockSite->FloatControlBar(m_pBar, m_ptMRUFloatPos, m_dwMRUFloatStyle);
  1478. }
  1479. }
  1480. void CMenuBar::OnPaintMDIClient()
  1481. {
  1482. LTRACE("CMenuBar::OnPaintMDIClientn");
  1483. if (m_hWndMDIClient) {
  1484. BOOL bMax = FALSE;
  1485. // get active MDI child window
  1486. HWND hWndChild = (HWND)::SendMessage(m_hWndMDIClient, WM_MDIGETACTIVE, 0,
  1487. (LPARAM)&bMax);
  1488. //ASSERT(::IsWindow(hWndChild)); crash! tell me why!
  1489. if (bMax != m_bMDIMaximized) {
  1490. LTRACE("    max state changedn");
  1491. m_bMDIMaximized = bMax;
  1492. if (bMax) {
  1493. LTRACE("        maximizedn");
  1494. m_pMenuControl->Validate(TRUE);
  1495. m_pMenuIcon->Validate(TRUE);
  1496. }
  1497. else {
  1498. LTRACE("        not maximizedn");
  1499. m_pMenuControl->Validate(FALSE);
  1500. m_pMenuIcon->Validate(FALSE);
  1501. }
  1502. RefreshBar();
  1503. }
  1504. }
  1505. }
  1506. void CMenuBar::OnInitMenuPopup()
  1507. {
  1508. CMenu menu;
  1509. menu.Attach((HMENU)m_hWindowMenu);
  1510. // scan for first window command
  1511. int n = menu.GetMenuItemCount();
  1512. BOOL bAddSeperator = TRUE;
  1513. for (int iPos=0; iPos<n; iPos++) {
  1514. if (menu.GetMenuItemID(iPos) >= AFX_IDM_FIRST_MDICHILD) {
  1515. bAddSeperator = FALSE;
  1516. break;
  1517. }
  1518. }
  1519. // iPos is either first window item, or end if none found.
  1520. // delete everything after.
  1521. while (iPos < (int)menu.GetMenuItemCount())
  1522. menu.RemoveMenu(iPos, MF_BYPOSITION);
  1523. // get active window so I can check its menu item
  1524. ASSERT(m_hWndMDIClient);
  1525. HWND hwndActive = (HWND)::SendMessage(m_hWndMDIClient,
  1526. WM_MDIGETACTIVE, 0, NULL);
  1527. // append window names in the form "# title"
  1528. int iWin=1;
  1529. for (HWND hwnd=::GetWindow(m_hWndMDIClient, GW_CHILD);
  1530.   hwnd;
  1531.   hwnd = ::GetWindow(hwnd, GW_HWNDNEXT)) {
  1532. if (bAddSeperator) {
  1533. menu.InsertMenu(iPos++, MF_BYPOSITION|MF_SEPARATOR);
  1534. bAddSeperator = FALSE;
  1535. }
  1536. // build item name and add it to the menu
  1537. CString sWinName, sMenuItem;
  1538. CWnd::FromHandle(hwnd)->GetWindowText(sWinName);
  1539. sMenuItem.Format(_T("&%d  %s"), iWin++, (LPCTSTR)sWinName);
  1540. menu.InsertMenu(iPos, MF_BYPOSITION,
  1541. ::GetDlgCtrlID(hwnd), sMenuItem);
  1542. if (hwnd==hwndActive)
  1543. menu.CheckMenuItem(iPos, MF_BYPOSITION|MF_CHECKED);
  1544. iPos++;
  1545. }
  1546. menu.Detach();
  1547. }
  1548. void CMenuBar::OnSetMenu(HMENU hNewMenu, HMENU hWindowMenu)
  1549. {
  1550. // We can get active MDI child window on this message!
  1551. BOOL bMax;
  1552. HWND hWndChild = GetActiveChildWnd(bMax);
  1553. if (!m_hWndActiveChild || m_hWndActiveChild != hWndChild) {
  1554. // active child window changed
  1555. LTRACE("    active child window changedn");
  1556. m_hWndActiveChild = hWndChild;
  1557. // tell MenuIcon child window has been changed
  1558. m_pMenuIcon->OnActivateChildWnd(hWndChild);
  1559. }
  1560. LTRACE("CMenuBar::OnSetMenun");
  1561. if (!m_hMenu || m_hMenu != hNewMenu) { // menu changed
  1562. LTRACE("    menu changedn");
  1563. LoadMenu(hNewMenu, hWindowMenu); // set toolbar menu
  1564. GetOwner()->SetMenu(NULL); // clear frame menu
  1565. }
  1566. }
  1567. HWND CMenuBar::GetActiveChildWnd(BOOL& bMaximized)
  1568. {
  1569. if (!m_hWndMDIClient)
  1570. return NULL;
  1571. BOOL bMax = FALSE;
  1572. HWND hWnd = (HWND)::SendMessage(m_hWndMDIClient,
  1573. WM_MDIGETACTIVE, 0, (LPARAM)&bMax);
  1574. bMaximized = bMax;
  1575. return hWnd;
  1576. }
  1577. CMenuItem::CMenuItem()
  1578. {
  1579. m_itemState = none;
  1580. m_rcItem = CRect(0, 0, 0, 0);
  1581. m_sizeHorz = CSize(0, 0);
  1582. m_bHorz = TRUE;
  1583. m_bWrapped = FALSE;
  1584. }
  1585. CMenuItem::~CMenuItem()
  1586. {
  1587. }
  1588. CPoint CMenuItem::ComputeMenuTrackPoint(CWnd* pWnd, HMENU hSubMenu, TPMPARAMS& tpm, CFont* pFont)
  1589. {
  1590. ASSERT_VALID(pWnd);
  1591. ASSERT_VALID(pFont);
  1592. ASSERT(::IsMenu(hSubMenu));
  1593. tpm.cbSize = sizeof(tpm);
  1594. CRect& rcExclude = (CRect&)tpm.rcExclude;
  1595. CWnd::GetDesktopWindow()->GetWindowRect(&rcExclude);
  1596. CPoint pt;
  1597. CRect  rcItem = m_rcItem;
  1598. pWnd->ClientToScreen(&rcItem);
  1599. // if (hSubMenu == NULL) // it's possible no sub menu
  1600. // return CPoint();
  1601. if (m_bHorz) { // horizontal
  1602. int nCount = ::GetMenuItemCount(hSubMenu);
  1603. ASSERT(nCount != -1);
  1604. int cyPopup = nCount * rcItem.Height(); // I want it be not owner drawn but ordinary menu..
  1605. if (rcItem.bottom + cyPopup > rcExclude.bottom) {
  1606. pt = CPoint(rcItem.left, rcItem.top); // over Screen
  1607. rcExclude.top = rcItem.top;
  1608. }
  1609. else {
  1610. pt = CPoint(rcItem.left, rcItem.bottom);
  1611. }
  1612. pt += CPoint(-1, 1); // precisely same as DevStudio
  1613. }
  1614. else { // vertical
  1615. // we never get the width of popup up menu, but I will try
  1616. int nCount = ::GetMenuItemCount(hSubMenu);
  1617. ASSERT(nCount != -1);
  1618. int cxPopup = 0;
  1619. CWindowDC dc(NULL);
  1620. CFont* pOldFont = dc.SelectObject(pFont);
  1621. for (int i = 0; i < nCount; ++i) {
  1622. char szName[256];
  1623. MENUITEMINFO info;
  1624. ::ZeroMemory(&info, sizeof(MENUITEMINFO));
  1625. info.cbSize = sizeof(MENUITEMINFO);
  1626. info.fMask = MIIM_ID | MIIM_TYPE;
  1627. info.dwTypeData = szName;
  1628. info.cch = sizeof(szName);
  1629. ::GetMenuItemInfo(hSubMenu, i, TRUE, &info);
  1630. CString strItem(szName);
  1631. CRect rcText(0, 0, 0, 0);
  1632. dc.DrawText(strItem, &rcText,
  1633. DT_SINGLELINE | DT_VCENTER | DT_CALCRECT | DT_NOPREFIX);
  1634. int cxOffset = ::GetSystemMetrics(SM_CXMENUCHECK) * 2;
  1635. cxPopup = max(rcText.Width() + 4*2 + CXGAP*2 + cxOffset, cxPopup);
  1636. }
  1637. dc.SelectObject(pOldFont);
  1638. if (rcItem.right + cxPopup > rcExclude.right) { // over right-side
  1639. pt = CPoint(rcItem.left, rcItem.top);
  1640. rcExclude.left = rcItem.left;
  1641. }
  1642. else {
  1643. pt = CPoint(rcItem.right, rcItem.top);
  1644. rcExclude.right = rcItem.right;
  1645. }
  1646. pt += CPoint(1, -1); // precisely same as DevStudio
  1647. }
  1648. return pt;
  1649. }
  1650. CMenuIcon::CMenuIcon(CWnd* pWnd)
  1651. {
  1652. m_hDocIcon = NULL;//hIcon;
  1653. m_sizeHorz = CSize(::GetSystemMetrics(SM_CXSMICON), ::GetSystemMetrics(SM_CYSMICON));
  1654. m_bValid = FALSE;
  1655. m_hSysMenu = NULL;//::GetSystemMenu(pWnd->GetSafeHwnd(), FALSE);
  1656. }
  1657. CMenuIcon::~CMenuIcon()
  1658. {
  1659. }
  1660. void CMenuIcon::Update(CDC* pDC)
  1661. {
  1662. ASSERT(m_hDocIcon);
  1663. ASSERT(m_bValid);
  1664. ::DrawIconEx(pDC->m_hDC, m_rcItem.left, m_rcItem.top, m_hDocIcon,
  1665. m_sizeHorz.cx, m_sizeHorz.cy, 0, NULL, DI_NORMAL);
  1666. }
  1667. void CMenuIcon::TrackPopup(CWnd* pWnd)
  1668. {
  1669. ASSERT(m_hDocIcon);
  1670. ASSERT(m_bValid);
  1671. ASSERT(::IsMenu(m_hSysMenu));
  1672. NONCLIENTMETRICS info;
  1673. info.cbSize = sizeof(info);
  1674. ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(info), &info, 0);
  1675. CFont fontSys;
  1676. if (!fontSys.CreateFontIndirect(&info.lfMenuFont))
  1677. return;
  1678. TPMPARAMS tpm;
  1679. CPoint pt = ComputeMenuTrackPoint(pWnd, m_hSysMenu, tpm, &fontSys);
  1680. ::TrackPopupMenuEx(m_hSysMenu,
  1681. TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_VERTICAL,
  1682. pt.x, pt.y, pWnd->GetOwner()->GetSafeHwnd(), &tpm);
  1683. }
  1684. void CMenuIcon::Layout(CPoint point, BOOL bHorz)
  1685. {
  1686. ASSERT(m_bValid);
  1687. m_bHorz = bHorz;
  1688. m_rcItem = CRect(point, m_sizeHorz);
  1689. }
  1690. void CMenuIcon::OnActivateChildWnd(HWND hWndChild)
  1691. {
  1692. //TRACE("CMenuIcon::OnActivateChildWndn");
  1693. ASSERT(::IsWindow(hWndChild));
  1694. m_hSysMenu = ::GetSystemMenu(hWndChild, FALSE);
  1695. ASSERT(::IsMenu(m_hSysMenu));
  1696. m_hDocIcon = (HICON)GetClassLong(hWndChild, GCL_HICONSM);
  1697. }
  1698. BOOL CMenuControl::OnMouseMsg(UINT msg, UINT nFlags, CPoint pt)
  1699. {
  1700. if (!IsValid())
  1701. return FALSE;
  1702. if (msg == WM_LBUTTONDOWN) {
  1703. m_nTracking = HitTest(pt);
  1704. if (m_nTracking >= 0) {
  1705. CClientDC dc(m_pBar);
  1706. DrawControl(&dc, m_nTracking, TRUE);
  1707. m_bDown = TRUE;
  1708. m_pBar->SetCapture();   // grab mouse input
  1709. return TRUE;
  1710. }
  1711. }
  1712. else if ((msg == WM_MOUSEMOVE) && m_nTracking >= 0) {
  1713. // mouse moved, and I am tracking: possibly draw button up/down
  1714. BOOL bOldDown = m_bDown;
  1715. m_bDown = m_arrCaption[m_nTracking].PtInRect(pt);
  1716. if (bOldDown != m_bDown) {
  1717. // up/down state changed: need to redraw button
  1718. CClientDC dc(m_pBar);
  1719. DrawControl(&dc, m_nTracking, m_bDown);
  1720. }
  1721. return TRUE; // handled
  1722. }
  1723. else if (msg == WM_LBUTTONUP && m_nTracking >= 0) {
  1724. // user released the mouse and I am tracking: do button command
  1725. ReleaseCapture(); // let go the mouse
  1726. if (m_bDown) {
  1727. // if button was down when released: draw button up, and do system cmd
  1728. CClientDC dc(m_pBar);
  1729. DrawControl(&dc, m_nTracking, FALSE);
  1730. CFrameWnd* pFrame = m_pBar->GetTopLevelFrame()->GetActiveFrame();
  1731. ASSERT_VALID(pFrame);
  1732. static syscmd[3] =
  1733. { /*SC_MOUSEMENU,*/ SC_CLOSE, SC_RESTORE, SC_MINIMIZE };
  1734. pFrame->SendMessage(WM_SYSCOMMAND, syscmd[m_nTracking]);
  1735. }
  1736. m_nTracking = -1; // stop tracking
  1737. return TRUE;   // handled (eat)
  1738. }
  1739. return FALSE;
  1740. }
  1741. int CMenuControl::HitTest(CPoint point)
  1742. {
  1743. for (int i = 0; i < 3; ++i) {
  1744. if (m_arrCaption[i].PtInRect(point))
  1745. return i;
  1746. }
  1747. return -1;
  1748. }
  1749. void CMenuControl::DrawControl(CDC* pDC, int nIndex, BOOL bPressed)
  1750. {
  1751. // draw frame controls
  1752. CRect& rc = m_arrCaption[nIndex];
  1753. static UINT dfcs[3] = { DFCS_CAPTIONCLOSE, DFCS_CAPTIONRESTORE, DFCS_CAPTIONMIN };
  1754. UINT uState = dfcs[nIndex];
  1755. if (bPressed)
  1756. uState |= DFCS_PUSHED;
  1757. pDC->DrawFrameControl(rc, DFC_CAPTION, uState);
  1758. }
  1759. void CMenuControl::ForceDrawControl(CDC * pDC)
  1760. {
  1761. if (!IsValid())
  1762. return;
  1763. for (int i = 0; i < 3; ++i) {
  1764. DrawControl(pDC, i, FALSE);
  1765. }
  1766. }
  1767. namespace {
  1768. const int CXTEXTMARGIN   = 5;
  1769. int CYTEXTMARGIN   = 0;
  1770. const int CYTEXTMARGINMIN = 2;
  1771. CFont fontHorz, fontVert;
  1772. // const int CXGAP = 3;
  1773. }// anonymouse namespace
  1774. CMenuButton::CMenuButton(HMENU hMenu, int nIndex)
  1775. {
  1776. ASSERT(hMenu);
  1777. InitButtonStringAndSubMenuHandle(hMenu, nIndex);
  1778. InitHorizontalButtonSize();
  1779. InitAccessKeyAndVerticalLinePoint();
  1780. }
  1781. CMenuButton::~CMenuButton()
  1782. {
  1783. }
  1784. BOOL CMenuButton::InitCommonResource()
  1785. {
  1786. // clean up
  1787. fontHorz.DeleteObject();
  1788. fontVert.DeleteObject();
  1789. // create fonts
  1790. NONCLIENTMETRICS info;
  1791. info.cbSize = sizeof(info);
  1792. ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(info), &info, 0);
  1793. if (!fontHorz.CreateFontIndirect(&info.lfMenuFont))
  1794. return FALSE;
  1795. info.lfMenuFont.lfEscapement = -900;
  1796. info.lfMenuFont.lfOrientation = -900;
  1797. if (!fontVert.CreateFontIndirect(&info.lfMenuFont))
  1798. return FALSE;
  1799. // get font height
  1800. LOGFONT logfont;
  1801. fontHorz.GetLogFont(&logfont);
  1802. int cyFont = abs(logfont.lfHeight);
  1803. // calc Y text margin
  1804. int cyText = cyFont + CYTEXTMARGINMIN*2;
  1805. int cyMenu = ::GetSystemMetrics(SM_CYMENU);
  1806. if (cyMenu > cyText) {
  1807. CYTEXTMARGIN = (cyMenu - cyFont)/2;
  1808. }
  1809. else {
  1810. CYTEXTMARGIN = CYTEXTMARGINMIN;
  1811. }
  1812. return TRUE;
  1813. }
  1814. void CMenuButton::InitButtonStringAndSubMenuHandle(HMENU hMenu, int nIndex)
  1815. {
  1816. // get menu button Text
  1817. char szText[256];
  1818. MENUITEMINFO info; ::ZeroMemory(&info, sizeof(MENUITEMINFO));
  1819. info.cbSize = sizeof(MENUITEMINFO);
  1820. info.fMask = MIIM_ID | MIIM_TYPE;
  1821. info.dwTypeData = szText;
  1822. info.cch = sizeof(szText);
  1823. ::GetMenuItemInfo(hMenu, nIndex, TRUE, &info);
  1824. m_strBtn = CString(szText);
  1825. m_hSubMenu = ::GetSubMenu(hMenu, nIndex);
  1826. }
  1827. void CMenuButton::InitHorizontalButtonSize()
  1828. {
  1829. // get menu button Text size
  1830. ASSERT(m_strBtn.IsEmpty() == FALSE);
  1831. CWindowDC dc(NULL);
  1832. CRect rcText(0, 0, 0, 0);
  1833. CFont* pOldFont = dc.SelectObject(&fontHorz);
  1834. dc.DrawText(m_strBtn, &rcText, DT_SINGLELINE | DT_CALCRECT);
  1835. dc.SelectObject(pOldFont);
  1836. m_sizeHorz.cx = rcText.Width() + CXTEXTMARGIN*2;
  1837. LOGFONT logfont;
  1838. fontHorz.GetLogFont(&logfont);
  1839. int cyFont = abs(logfont.lfHeight);
  1840. //this is decide the height of the menubar button
  1841. m_sizeHorz.cy = cyFont + CYTEXTMARGIN*2+2;
  1842. }
  1843. void CMenuButton::InitAccessKeyAndVerticalLinePoint()
  1844. {
  1845. int nIndex = m_strBtn.Find('&');
  1846. m_cAccessKey = m_strBtn[nIndex + 1]; // -1 + 1 = 0; it's ok
  1847. if (nIndex == -1) {
  1848. m_ptLineFrom = m_ptLineTo = CPoint(0, 0);
  1849. }
  1850. else if (nIndex == 0) {
  1851. CRect rcTo;
  1852. CWindowDC dc(NULL);
  1853. CFont* pOldFont = dc.SelectObject(&fontHorz);
  1854. dc.DrawText(m_strBtn.Left(nIndex+2), &rcTo, DT_SINGLELINE | DT_CALCRECT);
  1855. dc.SelectObject(pOldFont);
  1856. m_ptLineFrom = CPoint(CYTEXTMARGIN, CXTEXTMARGIN);
  1857. m_ptLineTo  = CPoint(CYTEXTMARGIN, CXTEXTMARGIN + rcTo.Width());
  1858. }
  1859. else {
  1860. CRect rcFrom, rcTo;
  1861. CWindowDC dc(NULL);
  1862. CFont* pOldFont = dc.SelectObject(&fontHorz);
  1863. dc.DrawText(m_strBtn.Left(nIndex), &rcFrom, DT_SINGLELINE | DT_CALCRECT);
  1864. dc.DrawText(m_strBtn.Left(nIndex+2), &rcTo, DT_SINGLELINE | DT_CALCRECT);
  1865. dc.SelectObject(pOldFont);
  1866. m_ptLineFrom = CPoint(CYTEXTMARGIN, CXTEXTMARGIN + rcFrom.Width());
  1867. m_ptLineTo = CPoint(CYTEXTMARGIN, CXTEXTMARGIN + rcTo.Width());
  1868. }
  1869. }
  1870. void CMenuButton::Layout(CPoint point, BOOL bHorz)
  1871. {
  1872. if (bHorz == TRUE) {
  1873. //this can change the rect of menubutton modify by xhs
  1874. CPoint p(point.x-3,point.y-2);
  1875. m_rcItem = CRect(p, m_sizeHorz);
  1876. }
  1877. else {
  1878. m_rcItem = CRect(point, CSize(m_sizeHorz.cy, m_sizeHorz.cx));
  1879. }
  1880. m_bHorz = bHorz;
  1881. }
  1882. void CMenuButton::Update(CDC* pDC)
  1883. {
  1884. // clean background
  1885. COLORREF clr = ::GetSysColor(COLOR_BTNFACE);
  1886. pDC->FillSolidRect(m_rcItem, clr);
  1887. switch (m_itemState) {
  1888. case hot:
  1889. DrawHot(pDC);
  1890. break;
  1891. case select:
  1892. DrawSelect(pDC);
  1893. break;
  1894. case none:
  1895. DrawNone(pDC);
  1896. break;
  1897. default:
  1898. ASSERT(TRUE);
  1899. }
  1900. }
  1901. void CMenuButton::TrackPopup(CWnd* pWnd)
  1902. {
  1903. TPMPARAMS tpm;
  1904. CPoint pt = ComputeMenuTrackPoint(pWnd, m_hSubMenu, tpm, &fontHorz);
  1905. ::TrackPopupMenuEx(m_hSubMenu,
  1906. TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_VERTICAL,
  1907. pt.x, pt.y, pWnd->GetOwner()->GetSafeHwnd(), &tpm);
  1908. }
  1909. void CMenuButton::DrawHorzText(CDC* pDC, CPoint ptOffset)
  1910. {
  1911. CRect rcBtn = m_rcItem;
  1912. pDC->SetBkMode(TRANSPARENT);
  1913. CFont* pOldFont = pDC->SelectObject(&fontHorz);
  1914. // I know precise text size
  1915. rcBtn.DeflateRect(CXTEXTMARGIN, CYTEXTMARGIN);
  1916. pDC->DrawText(m_strBtn, rcBtn + ptOffset,
  1917. DT_SINGLELINE);// | DT_CENTER | DT_VCENTER); no need
  1918. pDC->SelectObject(pOldFont);
  1919. }
  1920. void CMenuButton::DrawVertText(CDC* pDC, CPoint ptOffset)
  1921. {
  1922. CRect rcBtn = m_rcItem;
  1923. int nLength = m_strBtn.GetLength();
  1924. int nIndex = m_strBtn.Find('&');
  1925. CString strBtn = m_strBtn.Left(nIndex) + m_strBtn.Right(nLength - (nIndex+1));
  1926. pDC->SetBkMode(TRANSPARENT);
  1927. CFont* pOldFont = pDC->SelectObject(&fontVert);
  1928. // I must know precise text size
  1929. CRect rcString = CRect(
  1930. CPoint(rcBtn.right - CYTEXTMARGIN, rcBtn.top + CXTEXTMARGIN), m_sizeHorz);
  1931. pDC->DrawText(strBtn, rcString + ptOffset,
  1932. DT_SINGLELINE | DT_NOCLIP | DT_NOPREFIX); // don't forget DT_NOCLIP
  1933. pDC->SelectObject(pOldFont);
  1934. // DrawText is poor, so we have to draw vertical line by ourselves
  1935. pDC->MoveTo(rcBtn.TopLeft() + m_ptLineFrom + ptOffset);
  1936. pDC->LineTo(rcBtn.TopLeft() + m_ptLineTo + ptOffset);
  1937. }
  1938. void CMenuButton::DrawHot(CDC* pDC)
  1939. {
  1940. if (m_bHorz) {
  1941. // draw down button
  1942. pDC->DrawEdge(m_rcItem, BDR_RAISEDINNER, BF_RECT);
  1943. DrawHorzText(pDC);
  1944. }
  1945. else {
  1946. pDC->DrawEdge(m_rcItem, BDR_RAISEDINNER, BF_RECT);
  1947. DrawVertText(pDC);
  1948. }
  1949. }
  1950. void CMenuButton::DrawSelect(CDC* pDC)
  1951. {
  1952. if (m_bHorz) {
  1953. // draw pressed button
  1954. pDC->DrawEdge(m_rcItem, BDR_SUNKENOUTER, BF_RECT);
  1955. DrawHorzText(pDC, CPoint(1, 1));
  1956. }
  1957. else {
  1958. pDC->DrawEdge(m_rcItem, BDR_SUNKENOUTER, BF_RECT);
  1959. DrawVertText(pDC, CPoint(1, 1));
  1960. }
  1961. }
  1962. void CMenuButton::DrawNone(CDC* pDC)
  1963. {
  1964. if (m_bHorz) {
  1965. DrawHorzText(pDC);
  1966. }
  1967. else {
  1968. DrawVertText(pDC);
  1969. }
  1970. }
  1971. int CMenuBar::OnActivateFrame(int nCmdShow)
  1972. {
  1973. CFrameWnd* pFrame = GetParentFrame();
  1974. ASSERT_VALID(pFrame);
  1975. if (pFrame->GetMenu() != NULL) {
  1976. LTRACE(" has menun");
  1977. pFrame->SetMenu(NULL);
  1978. }
  1979. m_nCmdShow = nCmdShow;
  1980. return SW_HIDE;
  1981. }