PageRenderTime 52ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/ExtLibs/wxWidgets/src/os2/menu.cpp

https://bitbucket.org/lennonchan/cafu
C++ | 1175 lines | 824 code | 146 blank | 205 comment | 133 complexity | 9e35de49285e6ec5058e5ed2427de325 MD5 | raw file
  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name: src/os2/menu.cpp
  3. // Purpose: wxMenu, wxMenuBar, wxMenuItem
  4. // Author: David Webster
  5. // Modified by:
  6. // Created: 10/10/99
  7. // RCS-ID: $Id$
  8. // Copyright: (c) David Webster
  9. // Licence: wxWindows licence
  10. /////////////////////////////////////////////////////////////////////////////
  11. // For compilers that support precompilation, includes "wx.h".
  12. #include "wx/wxprec.h"
  13. #include "wx/menu.h"
  14. #ifndef WX_PRECOMP
  15. #include "wx/app.h"
  16. #include "wx/frame.h"
  17. #include "wx/utils.h"
  18. #include "wx/intl.h"
  19. #include "wx/log.h"
  20. #endif
  21. #if wxUSE_OWNER_DRAWN
  22. #include "wx/ownerdrw.h"
  23. #endif
  24. #include "wx/os2/private.h"
  25. // other standard headers
  26. #include <string.h>
  27. // ----------------------------------------------------------------------------
  28. // global variables
  29. // ----------------------------------------------------------------------------
  30. extern wxMenu* wxCurrentPopupMenu;
  31. // ----------------------------------------------------------------------------
  32. // constants
  33. // ----------------------------------------------------------------------------
  34. //
  35. // The (popup) menu title has this special id
  36. //
  37. static const int idMenuTitle = -3;
  38. //
  39. // The unique ID for Menus
  40. //
  41. USHORT wxMenu::m_nextMenuId = 0;
  42. // ----------------------------------------------------------------------------
  43. // macros
  44. // ----------------------------------------------------------------------------
  45. // ============================================================================
  46. // implementation
  47. // ============================================================================
  48. // ---------------------------------------------------------------------------
  49. // wxMenu construction, adding and removing menu items
  50. // ---------------------------------------------------------------------------
  51. //
  52. // Construct a menu with optional title (then use append)
  53. //
  54. void wxMenu::Init()
  55. {
  56. m_bDoBreak = false;
  57. m_nStartRadioGroup = -1;
  58. //
  59. // Create the menu (to be used as a submenu or a popup)
  60. //
  61. if ((m_hMenu = ::WinCreateWindow( HWND_DESKTOP
  62. ,WC_MENU
  63. ,"Menu"
  64. ,0L
  65. ,0L
  66. ,0L
  67. ,0L
  68. ,0L
  69. ,NULLHANDLE
  70. ,HWND_TOP
  71. ,0L
  72. ,NULL
  73. ,NULL
  74. )) == 0)
  75. {
  76. wxLogLastError(wxT("WinLoadMenu"));
  77. }
  78. m_vMenuData.iPosition = 0;
  79. m_vMenuData.afStyle = MIS_SUBMENU | MIS_TEXT;
  80. m_vMenuData.afAttribute = (USHORT)0;
  81. m_vMenuData.id = m_nextMenuId++;
  82. m_vMenuData.hwndSubMenu = m_hMenu;
  83. m_vMenuData.hItem = NULLHANDLE;
  84. //
  85. // If we have a title, insert it in the beginning of the menu
  86. //
  87. if (!m_title.empty())
  88. {
  89. Append( idMenuTitle
  90. ,m_title
  91. ,wxEmptyString
  92. ,wxITEM_NORMAL
  93. );
  94. AppendSeparator();
  95. }
  96. } // end of wxMenu::Init
  97. //
  98. // The wxWindow destructor will take care of deleting the submenus.
  99. //
  100. wxMenu::~wxMenu()
  101. {
  102. //
  103. // We should free PM resources only if PM doesn't do it for us
  104. // which happens if we're attached to a menubar or a submenu of another
  105. // menu
  106. if (!IsAttached() && !GetParent())
  107. {
  108. if (!::WinDestroyWindow((HWND)GetHmenu()) )
  109. {
  110. wxLogLastError(wxT("WinDestroyWindow"));
  111. }
  112. }
  113. #if wxUSE_ACCEL
  114. //
  115. // Delete accels
  116. //
  117. WX_CLEAR_ARRAY(m_vAccels);
  118. #endif // wxUSE_ACCEL
  119. } // end of wxMenu::~wxMenu
  120. void wxMenu::Break()
  121. {
  122. // this will take effect during the next call to Append()
  123. m_bDoBreak = true;
  124. } // end of wxMenu::Break
  125. void wxMenu::Attach(
  126. wxMenuBarBase* pMenubar
  127. )
  128. {
  129. wxMenuBase::Attach(pMenubar);
  130. EndRadioGroup();
  131. } // end of wxMenu::Break;
  132. #if wxUSE_ACCEL
  133. int wxMenu::FindAccel(
  134. int nId
  135. ) const
  136. {
  137. size_t n;
  138. size_t nCount = m_vAccels.GetCount();
  139. for (n = 0; n < nCount; n++)
  140. if (m_vAccels[n]->m_command == nId)
  141. return n;
  142. return wxNOT_FOUND;
  143. } // end of wxMenu::FindAccel
  144. void wxMenu::UpdateAccel(
  145. wxMenuItem* pItem
  146. )
  147. {
  148. if (pItem->IsSubMenu())
  149. {
  150. wxMenu* pSubmenu = pItem->GetSubMenu();
  151. wxMenuItemList::compatibility_iterator node = pSubmenu->GetMenuItems().GetFirst();
  152. while (node)
  153. {
  154. UpdateAccel(node->GetData());
  155. node = node->GetNext();
  156. }
  157. }
  158. else if (!pItem->IsSeparator())
  159. {
  160. //
  161. // Recurse upwards: we should only modify m_accels of the top level
  162. // menus, not of the submenus as wxMenuBar doesn't look at them
  163. // (alternative and arguable cleaner solution would be to recurse
  164. // downwards in GetAccelCount() and CopyAccels())
  165. //
  166. if (GetParent())
  167. {
  168. GetParent()->UpdateAccel(pItem);
  169. return;
  170. }
  171. //
  172. // Find the (new) accel for this item
  173. //
  174. wxAcceleratorEntry* pAccel = wxAcceleratorEntry::Create(pItem->GetItemLabel());
  175. if (pAccel)
  176. pAccel->m_command = pItem->GetId();
  177. //
  178. // Find the old one
  179. //
  180. size_t n = FindAccel(pItem->GetId());
  181. if (n == (size_t)wxNOT_FOUND)
  182. {
  183. //
  184. // No old, add new if any
  185. //
  186. if (pAccel)
  187. m_vAccels.Add(pAccel);
  188. else
  189. return;
  190. }
  191. else
  192. {
  193. //
  194. // Replace old with new or just remove the old one if no new
  195. //
  196. delete m_vAccels[n];
  197. if (pAccel)
  198. m_vAccels[n] = pAccel;
  199. else
  200. m_vAccels.RemoveAt(n);
  201. }
  202. if (IsAttached())
  203. {
  204. GetMenuBar()->RebuildAccelTable();
  205. }
  206. }
  207. } // wxMenu::UpdateAccel
  208. #endif // wxUSE_ACCEL
  209. //
  210. // Append a new item or submenu to the menu
  211. //
  212. bool wxMenu::DoInsertOrAppend( wxMenuItem* pItem,
  213. size_t nPos )
  214. {
  215. wxMenu* pSubmenu = pItem->GetSubMenu();
  216. MENUITEM& rItem = (pSubmenu != NULL)?pSubmenu->m_vMenuData:
  217. pItem->m_vMenuData;
  218. ERRORID vError;
  219. wxString sError;
  220. #if wxUSE_ACCEL
  221. UpdateAccel(pItem);
  222. #endif // wxUSE_ACCEL
  223. //
  224. // If "Break" has just been called, insert a menu break before this item
  225. // (and don't forget to reset the flag)
  226. //
  227. if (m_bDoBreak)
  228. {
  229. rItem.afStyle |= MIS_BREAK;
  230. m_bDoBreak = false;
  231. }
  232. //
  233. // Id is the numeric id for normal menu items and HMENU for submenus as
  234. // required by ::MM_INSERTITEM message API
  235. //
  236. if (pSubmenu != NULL)
  237. {
  238. wxASSERT_MSG(pSubmenu->GetHMenu(), wxT("invalid submenu"));
  239. pSubmenu->SetParent(this);
  240. rItem.iPosition = 0; // submenus have a 0 position
  241. rItem.id = (USHORT)pSubmenu->GetHMenu();
  242. rItem.afStyle |= MIS_SUBMENU | MIS_TEXT;
  243. }
  244. else
  245. {
  246. rItem.id = (USHORT)pItem->GetId();
  247. }
  248. char *pData = NULL;
  249. #if wxUSE_OWNER_DRAWN
  250. if (pItem->IsOwnerDrawn())
  251. {
  252. //
  253. // Want to get {Measure|Draw}Item messages?
  254. // item draws itself, passing pointer to data doesn't work in OS/2
  255. // Will eventually need to set the image handle somewhere into vItem.hItem
  256. //
  257. rItem.afStyle |= MIS_OWNERDRAW;
  258. pData = NULL;
  259. rItem.hItem = (HBITMAP)pItem->GetBitmap().GetHBITMAP();
  260. pItem->m_vMenuData.afStyle = rItem.afStyle;
  261. pItem->m_vMenuData.hItem = rItem.hItem;
  262. }
  263. else
  264. #endif
  265. if (pItem->IsSeparator())
  266. {
  267. rItem.afStyle = MIS_SEPARATOR;
  268. }
  269. else
  270. {
  271. if (pItem->GetId() == idMenuTitle)
  272. {
  273. // Item is an unselectable title to be passed via pData
  274. rItem.afStyle = MIS_STATIC;
  275. }
  276. else
  277. {
  278. //
  279. // Menu is just a normal string (passed in data parameter)
  280. //
  281. rItem.afStyle |= MIS_TEXT;
  282. }
  283. pData = (char*) pItem->GetItemLabel().wx_str();
  284. }
  285. if (nPos == (size_t)-1)
  286. {
  287. rItem.iPosition = MIT_END;
  288. }
  289. else
  290. {
  291. rItem.iPosition = (SHORT)nPos;
  292. }
  293. APIRET rc;
  294. rc = (APIRET)::WinSendMsg( GetHmenu()
  295. ,MM_INSERTITEM
  296. ,(MPARAM)&rItem
  297. ,(MPARAM)pData
  298. );
  299. #if wxUSE_OWNER_DRAWN
  300. if (pItem->IsOwnerDrawn())
  301. {
  302. MENUITEM vMenuItem;
  303. ::WinSendMsg( GetHmenu()
  304. ,MM_QUERYITEM
  305. ,MPFROM2SHORT( (USHORT)pItem->GetId()
  306. ,(USHORT)(FALSE)
  307. )
  308. ,&vMenuItem
  309. );
  310. }
  311. #endif
  312. if (rc == (APIRET)MIT_MEMERROR || rc == (APIRET)MIT_ERROR)
  313. {
  314. vError = ::WinGetLastError(vHabmain);
  315. sError = wxPMErrorToStr(vError);
  316. wxLogError(wxT("Error inserting or appending a menuitem. Error: %s\n"), sError.c_str());
  317. wxLogLastError(wxT("Insert or AppendMenu"));
  318. return false;
  319. }
  320. //
  321. // If we're already attached to the menubar, we must update it
  322. //
  323. if (IsAttached() && GetMenuBar()->IsAttached())
  324. {
  325. GetMenuBar()->Refresh();
  326. }
  327. return true;
  328. } // end of wxMenu::DoInsertOrAppend
  329. void wxMenu::EndRadioGroup()
  330. {
  331. //
  332. // We're not inside a radio group any longer
  333. //
  334. m_nStartRadioGroup = -1;
  335. } // end of wxMenu::EndRadioGroup
  336. wxMenuItem* wxMenu::DoAppend( wxMenuItem* pItem )
  337. {
  338. wxCHECK_MSG( pItem, NULL, wxT("NULL item in wxMenu::DoAppend") );
  339. bool bCheck = false;
  340. if (pItem->GetKind() == wxITEM_RADIO)
  341. {
  342. int nCount = GetMenuItemCount();
  343. if (m_nStartRadioGroup == -1)
  344. {
  345. //
  346. // Start a new radio group
  347. //
  348. m_nStartRadioGroup = nCount;
  349. //
  350. // For now it has just one element
  351. //
  352. pItem->SetAsRadioGroupStart();
  353. pItem->SetRadioGroupEnd(m_nStartRadioGroup);
  354. //
  355. // Ensure that we have a checked item in the radio group
  356. //
  357. bCheck = true;
  358. }
  359. else // extend the current radio group
  360. {
  361. //
  362. // We need to update its end item
  363. //
  364. pItem->SetRadioGroupStart(m_nStartRadioGroup);
  365. wxMenuItemList::compatibility_iterator node = GetMenuItems().Item(m_nStartRadioGroup);
  366. if (node)
  367. {
  368. node->GetData()->SetRadioGroupEnd(nCount);
  369. }
  370. else
  371. {
  372. wxFAIL_MSG( wxT("where is the radio group start item?") );
  373. }
  374. }
  375. }
  376. else // not a radio item
  377. {
  378. EndRadioGroup();
  379. }
  380. if (!wxMenuBase::DoAppend(pItem) || !DoInsertOrAppend(pItem))
  381. {
  382. return NULL;
  383. }
  384. if (bCheck)
  385. {
  386. //
  387. // Check the item initially
  388. //
  389. pItem->Check(true);
  390. }
  391. return pItem;
  392. } // end of wxMenu::DoAppend
  393. wxMenuItem* wxMenu::DoInsert(
  394. size_t nPos
  395. , wxMenuItem* pItem
  396. )
  397. {
  398. if ( wxMenuBase::DoInsert( nPos
  399. ,pItem) &&
  400. DoInsertOrAppend( pItem
  401. ,nPos
  402. ))
  403. return pItem;
  404. else
  405. return NULL;
  406. } // end of wxMenu::DoInsert
  407. wxMenuItem* wxMenu::DoRemove(
  408. wxMenuItem* pItem
  409. )
  410. {
  411. //
  412. // We need to find the items position in the child list
  413. //
  414. size_t nPos;
  415. wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst();
  416. for (nPos = 0; node; nPos++)
  417. {
  418. if (node->GetData() == pItem)
  419. break;
  420. node = node->GetNext();
  421. }
  422. //
  423. // DoRemove() (unlike Remove) can only be called for existing item!
  424. //
  425. wxCHECK_MSG(node, NULL, wxT("bug in wxMenu::Remove logic"));
  426. #if wxUSE_ACCEL
  427. //
  428. // Remove the corresponding accel from the accel table
  429. //
  430. int n = FindAccel(pItem->GetId());
  431. if (n != wxNOT_FOUND)
  432. {
  433. delete m_vAccels[n];
  434. m_vAccels.RemoveAt(n);
  435. }
  436. #endif // wxUSE_ACCEL
  437. //
  438. // Remove the item from the menu
  439. //
  440. ::WinSendMsg( GetHmenu()
  441. ,MM_REMOVEITEM
  442. ,MPFROM2SHORT(pItem->GetId(), TRUE)
  443. ,(MPARAM)0
  444. );
  445. if (IsAttached() && GetMenuBar()->IsAttached())
  446. {
  447. //
  448. // Otherwise, the chane won't be visible
  449. //
  450. GetMenuBar()->Refresh();
  451. }
  452. //
  453. // And from internal data structures
  454. //
  455. return wxMenuBase::DoRemove(pItem);
  456. } // end of wxMenu::DoRemove
  457. // ---------------------------------------------------------------------------
  458. // accelerator helpers
  459. // ---------------------------------------------------------------------------
  460. #if wxUSE_ACCEL
  461. //
  462. // Create the wxAcceleratorEntries for our accels and put them into provided
  463. // array - return the number of accels we have
  464. //
  465. size_t wxMenu::CopyAccels(
  466. wxAcceleratorEntry* pAccels
  467. ) const
  468. {
  469. size_t nCount = GetAccelCount();
  470. for (size_t n = 0; n < nCount; n++)
  471. {
  472. *pAccels++ = *m_vAccels[n];
  473. }
  474. return nCount;
  475. } // end of wxMenu::CopyAccels
  476. #endif // wxUSE_ACCEL
  477. // ---------------------------------------------------------------------------
  478. // set wxMenu title
  479. // ---------------------------------------------------------------------------
  480. void wxMenu::SetTitle( const wxString& rLabel )
  481. {
  482. bool bHasNoTitle = m_title.empty();
  483. HWND hMenu = GetHmenu();
  484. m_title = rLabel;
  485. if (bHasNoTitle)
  486. {
  487. if (!rLabel.empty())
  488. {
  489. if (!::WinSetWindowText(hMenu, rLabel.c_str()))
  490. {
  491. wxLogLastError(wxT("SetMenuTitle"));
  492. }
  493. }
  494. }
  495. else
  496. {
  497. if (rLabel.empty() )
  498. {
  499. ::WinSendMsg( GetHmenu()
  500. ,MM_REMOVEITEM
  501. ,MPFROM2SHORT(hMenu, TRUE)
  502. ,(MPARAM)0
  503. );
  504. }
  505. else
  506. {
  507. //
  508. // Modify the title
  509. //
  510. if (!::WinSetWindowText(hMenu, rLabel.c_str()))
  511. {
  512. wxLogLastError(wxT("SetMenuTitle"));
  513. }
  514. }
  515. }
  516. } // end of wxMenu::SetTitle
  517. // ---------------------------------------------------------------------------
  518. // event processing
  519. // ---------------------------------------------------------------------------
  520. bool wxMenu::OS2Command( WXUINT WXUNUSED(uParam),
  521. WXWORD vId )
  522. {
  523. //
  524. // Ignore commands from the menu title
  525. //
  526. if (vId != (WXWORD)idMenuTitle)
  527. {
  528. SendEvent( vId
  529. ,(int)::WinSendMsg( GetHmenu()
  530. ,MM_QUERYITEMATTR
  531. ,MPFROMSHORT(vId)
  532. ,(MPARAM)MIA_CHECKED
  533. )
  534. );
  535. }
  536. return true;
  537. } // end of wxMenu::OS2Command
  538. // ---------------------------------------------------------------------------
  539. // other
  540. // ---------------------------------------------------------------------------
  541. wxWindow* wxMenu::GetWindow() const
  542. {
  543. if (m_invokingWindow != NULL)
  544. return m_invokingWindow;
  545. else if ( GetMenuBar() != NULL)
  546. return GetMenuBar()->GetFrame();
  547. return NULL;
  548. } // end of wxMenu::GetWindow
  549. // recursive search for item by id
  550. wxMenuItem* wxMenu::FindItem(
  551. int nItemId
  552. , ULONG hItem
  553. , wxMenu** ppItemMenu
  554. ) const
  555. {
  556. if ( ppItemMenu )
  557. *ppItemMenu = NULL;
  558. wxMenuItem* pItem = NULL;
  559. for ( wxMenuItemList::compatibility_iterator node = m_items.GetFirst();
  560. node && !pItem;
  561. node = node->GetNext() )
  562. {
  563. pItem = node->GetData();
  564. if ( pItem->GetId() == nItemId && pItem->m_vMenuData.hItem == hItem)
  565. {
  566. if ( ppItemMenu )
  567. *ppItemMenu = (wxMenu *)this;
  568. }
  569. else if ( pItem->IsSubMenu() )
  570. {
  571. pItem = pItem->GetSubMenu()->FindItem( nItemId
  572. ,hItem
  573. ,ppItemMenu
  574. );
  575. if (pItem)
  576. break;
  577. }
  578. else
  579. {
  580. // don't exit the loop
  581. pItem = NULL;
  582. }
  583. }
  584. return pItem;
  585. } // end of wxMenu::FindItem
  586. // ---------------------------------------------------------------------------
  587. // Menu Bar
  588. // ---------------------------------------------------------------------------
  589. void wxMenuBar::Init()
  590. {
  591. m_eventHandler = this;
  592. m_menuBarFrame = NULL;
  593. m_hMenu = 0;
  594. } // end of wxMenuBar::Init
  595. wxMenuBar::wxMenuBar()
  596. {
  597. Init();
  598. } // end of wxMenuBar::wxMenuBar
  599. wxMenuBar::wxMenuBar(
  600. long WXUNUSED(lStyle)
  601. )
  602. {
  603. Init();
  604. } // end of wxMenuBar::wxMenuBar
  605. wxMenuBar::wxMenuBar(
  606. int nCount
  607. , wxMenu* vMenus[]
  608. , const wxString sTitles[]
  609. , long WXUNUSED(lStyle)
  610. )
  611. {
  612. Init();
  613. m_titles.Alloc(nCount);
  614. for ( int i = 0; i < nCount; i++ )
  615. {
  616. m_menus.Append(vMenus[i]);
  617. m_titles.Add(sTitles[i]);
  618. vMenus[i]->Attach(this);
  619. }
  620. } // end of wxMenuBar::wxMenuBar
  621. wxMenuBar::~wxMenuBar()
  622. {
  623. //
  624. // We should free PM's resources only if PM doesn't do it for us
  625. // which happens if we're attached to a frame
  626. //
  627. if (m_hMenu && !IsAttached())
  628. {
  629. ::WinDestroyWindow((HMENU)m_hMenu);
  630. m_hMenu = (WXHMENU)NULL;
  631. }
  632. } // end of wxMenuBar::~wxMenuBar
  633. // ---------------------------------------------------------------------------
  634. // wxMenuBar helpers
  635. // ---------------------------------------------------------------------------
  636. void wxMenuBar::Refresh()
  637. {
  638. wxCHECK_RET( IsAttached(), wxT("can't refresh unatteched menubar") );
  639. WinSendMsg(GetWinHwnd(m_menuBarFrame), WM_UPDATEFRAME, (MPARAM)FCF_MENU, (MPARAM)0);
  640. } // end of wxMenuBar::Refresh
  641. WXHMENU wxMenuBar::Create()
  642. {
  643. HWND hFrame;
  644. if (m_hMenu != 0 )
  645. return m_hMenu;
  646. wxCHECK_MSG(!m_hMenu, TRUE, wxT("menubar already created"));
  647. //
  648. // Menubars should be associated with a frame otherwise they are popups
  649. //
  650. if (m_menuBarFrame != NULL)
  651. hFrame = GetWinHwnd(m_menuBarFrame);
  652. else
  653. hFrame = HWND_DESKTOP;
  654. //
  655. // Create an empty menu and then fill it with insertions
  656. //
  657. if ((m_hMenu = ::WinCreateWindow( hFrame
  658. ,WC_MENU
  659. ,NULL
  660. ,MS_ACTIONBAR | WS_SYNCPAINT | WS_VISIBLE
  661. ,0L
  662. ,0L
  663. ,0L
  664. ,0L
  665. ,hFrame
  666. ,HWND_TOP
  667. ,FID_MENU
  668. ,NULL
  669. ,NULL
  670. )) == 0)
  671. {
  672. wxLogLastError(wxT("WinLoadMenu"));
  673. }
  674. else
  675. {
  676. size_t nCount = GetMenuCount(), i;
  677. wxMenuList::iterator it;
  678. for (i = 0, it = m_menus.begin(); i < nCount; i++, it++)
  679. {
  680. APIRET rc;
  681. ERRORID vError;
  682. wxString sError;
  683. HWND hSubMenu;
  684. //
  685. // Set the parent and owner of the submenues to be the menubar, not the desktop
  686. //
  687. hSubMenu = (*it)->m_vMenuData.hwndSubMenu;
  688. if (!::WinSetParent((*it)->m_vMenuData.hwndSubMenu, m_hMenu, FALSE))
  689. {
  690. vError = ::WinGetLastError(vHabmain);
  691. sError = wxPMErrorToStr(vError);
  692. wxLogError(wxT("Error setting parent for submenu. Error: %s\n"), sError.c_str());
  693. return NULLHANDLE;
  694. }
  695. if (!::WinSetOwner((*it)->m_vMenuData.hwndSubMenu, m_hMenu))
  696. {
  697. vError = ::WinGetLastError(vHabmain);
  698. sError = wxPMErrorToStr(vError);
  699. wxLogError(wxT("Error setting parent for submenu. Error: %s\n"), sError.c_str());
  700. return NULLHANDLE;
  701. }
  702. (*it)->m_vMenuData.iPosition = (SHORT)i;
  703. rc = (APIRET)::WinSendMsg(m_hMenu, MM_INSERTITEM, (MPARAM)&(*it)->m_vMenuData, (MPARAM)m_titles[i].wx_str());
  704. if (rc == (APIRET)MIT_MEMERROR || rc == (APIRET)MIT_ERROR)
  705. {
  706. vError = ::WinGetLastError(vHabmain);
  707. sError = wxPMErrorToStr(vError);
  708. wxLogError(wxT("Error inserting or appending a menuitem. Error: %s\n"), sError.c_str());
  709. return NULLHANDLE;
  710. }
  711. }
  712. }
  713. return m_hMenu;
  714. } // end of wxMenuBar::Create
  715. // ---------------------------------------------------------------------------
  716. // wxMenuBar functions to work with the top level submenus
  717. // ---------------------------------------------------------------------------
  718. //
  719. // NB: we don't support owner drawn top level items for now, if we do these
  720. // functions would have to be changed to use wxMenuItem as well
  721. //
  722. void wxMenuBar::EnableTop(
  723. size_t nPos
  724. , bool bEnable
  725. )
  726. {
  727. wxCHECK_RET(IsAttached(), wxT("doesn't work with unattached menubars"));
  728. USHORT uFlag = 0;
  729. SHORT nId;
  730. if(!bEnable)
  731. uFlag = MIA_DISABLED;
  732. nId = SHORT1FROMMR(::WinSendMsg((HWND)m_hMenu, MM_ITEMIDFROMPOSITION, MPFROMSHORT(nPos), (MPARAM)0));
  733. if (nId == MIT_ERROR)
  734. {
  735. wxLogLastError(wxT("LogLastError"));
  736. return;
  737. }
  738. ::WinSendMsg((HWND)m_hMenu, MM_SETITEMATTR, MPFROM2SHORT(nId, TRUE), MPFROM2SHORT(MIA_DISABLED, uFlag));
  739. Refresh();
  740. } // end of wxMenuBar::EnableTop
  741. void wxMenuBar::SetMenuLabel(
  742. size_t nPos
  743. , const wxString& rLabel
  744. )
  745. {
  746. SHORT nId;
  747. MENUITEM vItem;
  748. wxCHECK_RET(nPos < GetMenuCount(), wxT("invalid menu index"));
  749. m_titles[nPos] = rLabel;
  750. if (!IsAttached())
  751. {
  752. return;
  753. }
  754. nId = SHORT1FROMMR(::WinSendMsg((HWND)m_hMenu, MM_ITEMIDFROMPOSITION, MPFROMSHORT(nPos), (MPARAM)0));
  755. if (nId == MIT_ERROR)
  756. {
  757. wxLogLastError(wxT("LogLastError"));
  758. return;
  759. }
  760. if(!::WinSendMsg( (HWND)m_hMenu
  761. ,MM_QUERYITEM
  762. ,MPFROM2SHORT(nId, TRUE)
  763. ,MPARAM(&vItem)
  764. ))
  765. {
  766. wxLogLastError(wxT("QueryItem"));
  767. }
  768. nId = vItem.id;
  769. if (::WinSendMsg(GetHmenu(), MM_SETITEMTEXT, MPFROMSHORT(nId), (MPARAM)rLabel.wx_str()));
  770. {
  771. wxLogLastError(wxT("ModifyMenu"));
  772. }
  773. Refresh();
  774. } // end of wxMenuBar::SetMenuLabel
  775. wxString wxMenuBar::GetMenuLabel(
  776. size_t nPos
  777. ) const
  778. {
  779. wxCHECK_MSG( nPos < GetMenuCount(), wxEmptyString,
  780. wxT("invalid menu index in wxMenuBar::GetMenuLabel") );
  781. return m_titles[nPos];
  782. } // end of wxMenuBar::GetMenuLabel
  783. // ---------------------------------------------------------------------------
  784. // wxMenuBar construction
  785. // ---------------------------------------------------------------------------
  786. wxMenu* wxMenuBar::Replace(
  787. size_t nPos
  788. , wxMenu* pMenu
  789. , const wxString& rTitle
  790. )
  791. {
  792. SHORT nId;
  793. wxString sTitle = wxPMTextToLabel(rTitle);
  794. wxMenu* pMenuOld = wxMenuBarBase::Replace( nPos
  795. ,pMenu
  796. ,sTitle
  797. );
  798. nId = SHORT1FROMMR(::WinSendMsg((HWND)m_hMenu, MM_ITEMIDFROMPOSITION, MPFROMSHORT(nPos), (MPARAM)0));
  799. if (nId == MIT_ERROR)
  800. {
  801. wxLogLastError(wxT("LogLastError"));
  802. return NULL;
  803. }
  804. if (!pMenuOld)
  805. return NULL;
  806. m_titles[nPos] = sTitle;
  807. if (IsAttached())
  808. {
  809. ::WinSendMsg((HWND)m_hMenu, MM_REMOVEITEM, MPFROM2SHORT(nId, TRUE), (MPARAM)0);
  810. ::WinSendMsg((HWND)m_hMenu, MM_INSERTITEM, (MPARAM)&pMenu->m_vMenuData, (MPARAM)sTitle.wx_str());
  811. #if wxUSE_ACCEL
  812. if (pMenuOld->HasAccels() || pMenu->HasAccels())
  813. {
  814. //
  815. // Need to rebuild accell table
  816. //
  817. RebuildAccelTable();
  818. }
  819. #endif // wxUSE_ACCEL
  820. Refresh();
  821. }
  822. return pMenuOld;
  823. } // end of wxMenuBar::Replace
  824. bool wxMenuBar::Insert( size_t nPos,
  825. wxMenu* pMenu,
  826. const wxString& rTitle )
  827. {
  828. wxString sTitle = wxPMTextToLabel(rTitle);
  829. if (!wxMenuBarBase::Insert( nPos, pMenu, sTitle ))
  830. return false;
  831. m_titles.Insert( sTitle, nPos );
  832. if (IsAttached())
  833. {
  834. pMenu->m_vMenuData.iPosition = (SHORT)nPos;
  835. ::WinSendMsg( (HWND)m_hMenu
  836. ,MM_INSERTITEM
  837. ,(MPARAM)&pMenu->m_vMenuData
  838. ,(MPARAM)sTitle.wx_str()
  839. );
  840. #if wxUSE_ACCEL
  841. if (pMenu->HasAccels())
  842. {
  843. // need to rebuild accell table
  844. RebuildAccelTable();
  845. }
  846. #endif // wxUSE_ACCEL
  847. Refresh();
  848. }
  849. return true;
  850. } // end of wxMenuBar::Insert
  851. bool wxMenuBar::Append( wxMenu* pMenu,
  852. const wxString& rsTitle )
  853. {
  854. WXHMENU hSubmenu = pMenu ? pMenu->GetHMenu() : 0;
  855. wxCHECK_MSG(hSubmenu, false, wxT("can't append invalid menu to menubar"));
  856. wxString sTitle = wxPMTextToLabel(rsTitle);
  857. if (!wxMenuBarBase::Append(pMenu, sTitle))
  858. return false;
  859. m_titles.Add(sTitle);
  860. if ( IsAttached() )
  861. {
  862. pMenu->m_vMenuData.iPosition = MIT_END;
  863. ::WinSendMsg((HWND)m_hMenu, MM_INSERTITEM, (MPARAM)&pMenu->m_vMenuData, (MPARAM)sTitle.wx_str());
  864. #if wxUSE_ACCEL
  865. if (pMenu->HasAccels())
  866. {
  867. //
  868. // Need to rebuild accell table
  869. //
  870. RebuildAccelTable();
  871. }
  872. #endif // wxUSE_ACCEL
  873. Refresh();
  874. }
  875. return true;
  876. } // end of wxMenuBar::Append
  877. wxMenu* wxMenuBar::Remove(
  878. size_t nPos
  879. )
  880. {
  881. wxMenu* pMenu = wxMenuBarBase::Remove(nPos);
  882. SHORT nId;
  883. if (!pMenu)
  884. return NULL;
  885. nId = SHORT1FROMMR(::WinSendMsg( (HWND)GetHmenu()
  886. ,MM_ITEMIDFROMPOSITION
  887. ,MPFROMSHORT(nPos)
  888. ,(MPARAM)0)
  889. );
  890. if (nId == MIT_ERROR)
  891. {
  892. wxLogLastError(wxT("LogLastError"));
  893. return NULL;
  894. }
  895. if (IsAttached())
  896. {
  897. ::WinSendMsg( (HWND)GetHmenu()
  898. ,MM_REMOVEITEM
  899. ,MPFROM2SHORT(nId, TRUE)
  900. ,(MPARAM)0
  901. );
  902. #if wxUSE_ACCEL
  903. if (pMenu->HasAccels())
  904. {
  905. //
  906. // Need to rebuild accell table
  907. //
  908. RebuildAccelTable();
  909. }
  910. #endif // wxUSE_ACCEL
  911. Refresh();
  912. }
  913. m_titles.RemoveAt(nPos);
  914. return pMenu;
  915. } // end of wxMenuBar::Remove
  916. #if wxUSE_ACCEL
  917. void wxMenuBar::RebuildAccelTable()
  918. {
  919. //
  920. // Merge the accelerators of all menus into one accel table
  921. //
  922. size_t nAccelCount = 0;
  923. size_t i;
  924. size_t nCount = GetMenuCount();
  925. wxMenuList::iterator it;
  926. for (i = 0, it = m_menus.begin(); i < nCount; i++, it++)
  927. {
  928. nAccelCount += (*it)->GetAccelCount();
  929. }
  930. if (nAccelCount)
  931. {
  932. wxAcceleratorEntry* pAccelEntries = new wxAcceleratorEntry[nAccelCount];
  933. nAccelCount = 0;
  934. for (i = 0, it = m_menus.begin(); i < nCount; i++, it++)
  935. {
  936. nAccelCount += (*it)->CopyAccels(&pAccelEntries[nAccelCount]);
  937. }
  938. m_vAccelTable = wxAcceleratorTable( nAccelCount
  939. ,pAccelEntries
  940. );
  941. delete [] pAccelEntries;
  942. }
  943. } // end of wxMenuBar::RebuildAccelTable
  944. #endif // wxUSE_ACCEL
  945. void wxMenuBar::Attach(
  946. wxFrame* pFrame
  947. )
  948. {
  949. wxMenuBarBase::Attach(pFrame);
  950. #if wxUSE_ACCEL
  951. RebuildAccelTable();
  952. //
  953. // Ensure the accelerator table is set to the frame (not the client!)
  954. //
  955. if (!::WinSetAccelTable( vHabmain
  956. ,m_vAccelTable.GetHACCEL()
  957. ,(HWND)pFrame->GetFrame()
  958. ))
  959. {
  960. wxLogLastError(wxT("WinSetAccelTable"));
  961. }
  962. #endif // wxUSE_ACCEL
  963. } // end of wxMenuBar::Attach
  964. void wxMenuBar::Detach()
  965. {
  966. ::WinDestroyWindow((HWND)m_hMenu);
  967. m_hMenu = (WXHMENU)NULL;
  968. m_menuBarFrame = NULL;
  969. } // end of wxMenuBar::Detach
  970. // ---------------------------------------------------------------------------
  971. // wxMenuBar searching for menu items
  972. // ---------------------------------------------------------------------------
  973. //
  974. // Find the itemString in menuString, and return the item id or wxNOT_FOUND
  975. //
  976. int wxMenuBar::FindMenuItem(
  977. const wxString& rMenuString
  978. , const wxString& rItemString
  979. ) const
  980. {
  981. wxString sMenuLabel = wxStripMenuCodes(rMenuString);
  982. size_t nCount = GetMenuCount(), i;
  983. wxMenuList::const_iterator it;
  984. for (i = 0, it = m_menus.begin(); i < nCount; i++, it++)
  985. {
  986. wxString sTitle = wxStripMenuCodes(m_titles[i]);
  987. if (rMenuString == sTitle)
  988. return (*it)->FindItem(rItemString);
  989. }
  990. return wxNOT_FOUND;
  991. } // end of wxMenuBar::FindMenuItem
  992. wxMenuItem* wxMenuBar::FindItem(
  993. int nId
  994. , wxMenu** ppItemMenu
  995. ) const
  996. {
  997. if (ppItemMenu)
  998. *ppItemMenu = NULL;
  999. wxMenuItem* pItem = NULL;
  1000. size_t nCount = GetMenuCount(), i;
  1001. wxMenuList::const_iterator it;
  1002. for (i = 0, it = m_menus.begin(); !pItem && (i < nCount); i++, it++)
  1003. {
  1004. pItem = (*it)->FindItem( nId
  1005. ,ppItemMenu
  1006. );
  1007. }
  1008. return pItem;
  1009. } // end of wxMenuBar::FindItem
  1010. wxMenuItem* wxMenuBar::FindItem(
  1011. int nId
  1012. , ULONG hItem
  1013. , wxMenu** ppItemMenu
  1014. ) const
  1015. {
  1016. if (ppItemMenu)
  1017. *ppItemMenu = NULL;
  1018. wxMenuItem* pItem = NULL;
  1019. size_t nCount = GetMenuCount(), i;
  1020. wxMenuList::const_iterator it;
  1021. for (i = 0, it = m_menus.begin(); !pItem && (i < nCount); i++, it++)
  1022. {
  1023. pItem = (*it)->FindItem( nId
  1024. ,hItem
  1025. ,ppItemMenu
  1026. );
  1027. }
  1028. return pItem;
  1029. } // end of wxMenuBar::FindItem