PageRenderTime 148ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/Dependencies/wxWidgets/src/osx/carbon/menu.cpp

https://github.com/goofoo/Helium
C++ | 420 lines | 314 code | 61 blank | 45 comment | 54 complexity | 98d6dcd0311685efeeaa7bc2b8dc526f MD5 | raw file
  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name: src/osx/carbon/menu.cpp
  3. // Purpose: wxMenu, wxMenuBar, wxMenuItem
  4. // Author: Stefan Csomor
  5. // Modified by:
  6. // Created: 1998-01-01
  7. // RCS-ID: $Id$
  8. // Copyright: (c) Stefan Csomor
  9. // Licence: wxWindows licence
  10. /////////////////////////////////////////////////////////////////////////////
  11. // ============================================================================
  12. // headers & declarations
  13. // ============================================================================
  14. // wxWidgets headers
  15. // -----------------
  16. #include "wx/wxprec.h"
  17. #include "wx/menu.h"
  18. #ifndef WX_PRECOMP
  19. #include "wx/log.h"
  20. #include "wx/app.h"
  21. #include "wx/utils.h"
  22. #include "wx/frame.h"
  23. #include "wx/menuitem.h"
  24. #endif
  25. #include "wx/osx/private.h"
  26. #include "wx/stockitem.h"
  27. // other standard headers
  28. // ----------------------
  29. #include <string.h>
  30. // under carbon there's no such thing as a MenuItemRef, everything is done
  31. // on the 'parent' menu via index APIs (first line having index 1 !)
  32. // so to make things still work, we store the wxMenuItemImpl instance as a
  33. // RefCon at the respective menu line
  34. class wxMenuItemCarbonImpl : public wxMenuItemImpl
  35. {
  36. public :
  37. wxMenuItemCarbonImpl( wxMenuItem* peer ) : wxMenuItemImpl(peer)
  38. {
  39. // the parent menu ref is only set, once the item has been attached
  40. m_parentMenuRef = NULL;
  41. }
  42. ~wxMenuItemCarbonImpl();
  43. void SetBitmap( const wxBitmap& bitmap )
  44. {
  45. MenuItemIndex i = FindMenuItemIndex() ;
  46. if ( i > 0 )
  47. {
  48. if ( bitmap.Ok() )
  49. {
  50. #if wxUSE_BMPBUTTON
  51. ControlButtonContentInfo info ;
  52. wxMacCreateBitmapButton( &info , bitmap ) ;
  53. if ( info.contentType != kControlNoContent )
  54. {
  55. if ( info.contentType == kControlContentIconRef )
  56. SetMenuItemIconHandle( m_parentMenuRef, i ,
  57. kMenuIconRefType , (Handle) info.u.iconRef ) ;
  58. else if ( info.contentType == kControlContentCGImageRef )
  59. SetMenuItemIconHandle( m_parentMenuRef, i ,
  60. kMenuCGImageRefType , (Handle) info.u.imageRef ) ;
  61. }
  62. wxMacReleaseBitmapButton( &info ) ;
  63. #endif
  64. }
  65. }
  66. }
  67. void Enable( bool enable )
  68. {
  69. MenuItemIndex i = FindMenuItemIndex() ;
  70. if ( i > 0 )
  71. {
  72. if ( GetWXPeer()->GetId() == wxApp::s_macPreferencesMenuItemId)
  73. {
  74. if ( enable )
  75. EnableMenuCommand( NULL , kHICommandPreferences ) ;
  76. else
  77. DisableMenuCommand( NULL , kHICommandPreferences ) ;
  78. }
  79. else if ( GetWXPeer()->GetId() == wxApp::s_macExitMenuItemId)
  80. {
  81. if ( enable )
  82. EnableMenuCommand( NULL , kHICommandQuit ) ;
  83. else
  84. DisableMenuCommand( NULL , kHICommandQuit ) ;
  85. }
  86. if ( enable )
  87. EnableMenuItem(m_parentMenuRef , i);
  88. else
  89. DisableMenuItem(m_parentMenuRef , i);
  90. if ( GetWXPeer()->IsSubMenu() )
  91. {
  92. UMAEnableMenuItem( GetWXPeer()->GetSubMenu()->GetHMenu() , 0 , enable ) ;
  93. }
  94. }
  95. }
  96. void Check( bool check )
  97. {
  98. MenuItemIndex i = FindMenuItemIndex() ;
  99. if ( i > 0 )
  100. {
  101. if ( check )
  102. ::SetItemMark( m_parentMenuRef, i, 0x12 ) ; // checkmark
  103. else
  104. ::SetItemMark( m_parentMenuRef, i, 0 ) ; // no mark
  105. }
  106. }
  107. void Hide( bool hide )
  108. {
  109. MenuItemIndex i = FindMenuItemIndex() ;
  110. if ( i > 0 )
  111. {
  112. if ( hide )
  113. ChangeMenuItemAttributes( m_parentMenuRef, i, kMenuItemAttrHidden, 0 );
  114. else
  115. ChangeMenuItemAttributes( m_parentMenuRef, i, 0 , kMenuItemAttrHidden );
  116. }
  117. }
  118. void SetLabel( const wxString& text, wxAcceleratorEntry *entry )
  119. {
  120. MenuItemIndex i = FindMenuItemIndex() ;
  121. if ( i > 0 )
  122. {
  123. SetMenuItemTextWithCFString( m_parentMenuRef, i, wxCFStringRef(text));
  124. UMASetMenuItemShortcut( m_parentMenuRef, i , entry ) ;
  125. }
  126. }
  127. void * GetHMenuItem() { return NULL; }
  128. // Carbon Only
  129. void AttachToParent( MenuRef parentMenuRef, MenuItemIndex index )
  130. {
  131. m_parentMenuRef = parentMenuRef;
  132. if ( m_parentMenuRef && index > 0 )
  133. SetMenuItemRefCon( m_parentMenuRef, index, (URefCon) m_peer );
  134. }
  135. MenuItemIndex FindMenuItemIndex()
  136. {
  137. MenuItemIndex hit = 0 ;
  138. if ( m_parentMenuRef )
  139. {
  140. for ( MenuItemIndex i = 1 ; i <= CountMenuItems(m_parentMenuRef) ; ++i )
  141. {
  142. URefCon storedRef = 0;
  143. GetMenuItemRefCon(m_parentMenuRef, i, &storedRef );
  144. if ( storedRef == (URefCon) m_peer )
  145. {
  146. hit = i;
  147. break;
  148. }
  149. }
  150. }
  151. return hit;
  152. }
  153. protected :
  154. MenuRef m_parentMenuRef;
  155. } ;
  156. //
  157. // wxMenuImpl
  158. //
  159. class wxMenuCarbonImpl : public wxMenuImpl
  160. {
  161. public :
  162. wxMenuCarbonImpl( wxMenu* peer , MenuRef menu) : wxMenuImpl(peer), m_osxMenu(menu)
  163. {
  164. }
  165. virtual ~wxMenuCarbonImpl();
  166. virtual void InsertOrAppend(wxMenuItem *pItem, size_t pos)
  167. {
  168. // MacOS counts menu items from 1 and inserts after, therefore having the
  169. // same effect as wx 0 based and inserting before, we must correct pos
  170. // after however for updates to be correct
  171. MenuItemIndex index = pos;
  172. if ( pos == (size_t) -1 )
  173. index = CountMenuItems(m_osxMenu);
  174. if ( pItem->IsSeparator() )
  175. {
  176. InsertMenuItemTextWithCFString( m_osxMenu, CFSTR(""), index, kMenuItemAttrSeparator, 0);
  177. // now switch to the Carbon 1 based counting
  178. index += 1 ;
  179. }
  180. else
  181. {
  182. InsertMenuItemTextWithCFString( m_osxMenu, CFSTR("placeholder"), index, 0, 0 );
  183. // now switch to the Carbon 1 based counting
  184. index += 1 ;
  185. if ( pItem->IsSubMenu() )
  186. {
  187. MenuRef submenu = pItem->GetSubMenu()->GetHMenu();
  188. SetMenuItemHierarchicalMenu(m_osxMenu, index, submenu);
  189. // carbon is using the title of the submenu, eg in the menubar
  190. SetMenuTitleWithCFString(submenu, wxCFStringRef(pItem->GetItemLabelText()));
  191. }
  192. else
  193. {
  194. SetMenuItemCommandID( m_osxMenu, index , wxIdToMacCommand(pItem->GetId()) ) ;
  195. }
  196. }
  197. wxMenuItemCarbonImpl* impl = (wxMenuItemCarbonImpl*) pItem->GetPeer();
  198. impl->AttachToParent( m_osxMenu, index );
  199. // only now can all settings be updated correctly
  200. pItem->UpdateItemText();
  201. pItem->UpdateItemStatus();
  202. pItem->UpdateItemBitmap();
  203. }
  204. virtual void Remove( wxMenuItem *pItem )
  205. {
  206. wxMenuItemCarbonImpl* impl = (wxMenuItemCarbonImpl*) pItem->GetPeer();
  207. if ( impl )
  208. {
  209. MenuItemIndex i = impl->FindMenuItemIndex();
  210. if ( i > 0 )
  211. {
  212. DeleteMenuItem(m_osxMenu , i);
  213. impl->AttachToParent( NULL, 0 );
  214. }
  215. }
  216. }
  217. virtual void MakeRoot()
  218. {
  219. SetRootMenu( m_osxMenu );
  220. }
  221. virtual void SetTitle( const wxString& text )
  222. {
  223. SetMenuTitleWithCFString(m_osxMenu, wxCFStringRef(text));
  224. }
  225. WXHMENU GetHMenu() { return m_osxMenu; }
  226. virtual void PopUp( wxWindow *WXUNUSED(win), int x, int y )
  227. {
  228. long menuResult = ::PopUpMenuSelect(m_osxMenu, y, x, 0) ;
  229. if ( HiWord(menuResult) != 0 )
  230. {
  231. MenuCommand macid;
  232. GetMenuItemCommandID( GetMenuHandle(HiWord(menuResult)) , LoWord(menuResult) , &macid );
  233. int id = wxMacCommandToId( macid );
  234. wxMenuItem* item = NULL ;
  235. wxMenu* realmenu ;
  236. item = m_peer->FindItem( id, &realmenu ) ;
  237. if ( item )
  238. {
  239. m_peer->HandleCommandProcess(item, NULL );
  240. }
  241. }
  242. }
  243. static wxMenuImpl* Create( wxMenu* peer, const wxString& title );
  244. static wxMenuImpl* CreateRootMenu( wxMenu* peer );
  245. protected :
  246. wxCFRef<MenuRef> m_osxMenu;
  247. } ;
  248. // static const short kwxMacAppleMenuId = 1 ;
  249. // Find an item given the Macintosh Menu Reference
  250. WX_DECLARE_HASH_MAP(WXHMENU, wxMenu*, wxPointerHash, wxPointerEqual, MacMenuMap);
  251. static MacMenuMap wxWinMacMenuList;
  252. wxMenu *wxFindMenuFromMacMenu(WXHMENU inMenuRef)
  253. {
  254. MacMenuMap::iterator node = wxWinMacMenuList.find(inMenuRef);
  255. return (node == wxWinMacMenuList.end()) ? NULL : node->second;
  256. }
  257. void wxAssociateMenuWithMacMenu(WXHMENU inMenuRef, wxMenu *menu) ;
  258. void wxAssociateMenuWithMacMenu(WXHMENU inMenuRef, wxMenu *menu)
  259. {
  260. // adding NULL MenuRef is (first) surely a result of an error and
  261. // (secondly) breaks menu command processing
  262. wxCHECK_RET( inMenuRef != (WXHMENU) NULL, wxT("attempt to add a NULL MenuRef to menu list") );
  263. wxWinMacMenuList[inMenuRef] = menu;
  264. }
  265. void wxRemoveMacMenuAssociation(wxMenu *menu) ;
  266. void wxRemoveMacMenuAssociation(wxMenu *menu)
  267. {
  268. // iterate over all the elements in the class
  269. MacMenuMap::iterator it;
  270. for ( it = wxWinMacMenuList.begin(); it != wxWinMacMenuList.end(); ++it )
  271. {
  272. if ( it->second == menu )
  273. {
  274. wxWinMacMenuList.erase(it);
  275. break;
  276. }
  277. }
  278. }
  279. wxMenuCarbonImpl::~wxMenuCarbonImpl()
  280. {
  281. wxRemoveMacMenuAssociation( GetWXPeer() );
  282. }
  283. wxMenuImpl* wxMenuImpl::Create( wxMenu* peer, const wxString& title )
  284. {
  285. // create the menu
  286. static SInt16 s_macNextMenuId = 3;
  287. WXHMENU menu = NULL;
  288. CreateNewMenu( s_macNextMenuId++ , 0 , &menu ) ;
  289. if ( !menu )
  290. {
  291. wxLogLastError(wxT("CreateNewMenu failed"));
  292. return NULL;
  293. }
  294. wxMenuImpl* c = new wxMenuCarbonImpl( peer, menu );
  295. c->SetTitle(title);
  296. wxAssociateMenuWithMacMenu( menu , peer ) ;
  297. return c;
  298. }
  299. //
  300. //
  301. //
  302. wxMenuItemCarbonImpl::~wxMenuItemCarbonImpl()
  303. {
  304. }
  305. wxMenuItemImpl* wxMenuItemImpl::Create( wxMenuItem* peer,
  306. wxMenu * WXUNUSED(pParentMenu),
  307. int WXUNUSED(id),
  308. const wxString& WXUNUSED(text),
  309. wxAcceleratorEntry *WXUNUSED(entry),
  310. const wxString& WXUNUSED(strHelp),
  311. wxItemKind WXUNUSED(kind),
  312. wxMenu *WXUNUSED(pSubMenu) )
  313. {
  314. wxMenuItemImpl* c = NULL;
  315. c = new wxMenuItemCarbonImpl( peer );
  316. return c;
  317. }
  318. void wxInsertMenuItemsInMenu(wxMenu* menu, MenuRef wm, MenuItemIndex insertAfter)
  319. {
  320. wxMenuItemList::compatibility_iterator node;
  321. wxMenuItem *item;
  322. wxMenu *subMenu = NULL ;
  323. bool newItems = false;
  324. for (node = menu->GetMenuItems().GetFirst(); node; node = node->GetNext())
  325. {
  326. item = (wxMenuItem *)node->GetData();
  327. subMenu = item->GetSubMenu() ;
  328. if (subMenu)
  329. {
  330. wxInsertMenuItemsInMenu(subMenu, (MenuRef)subMenu->GetHMenu(), 0);
  331. }
  332. if ( item->IsSeparator() )
  333. {
  334. if ( wm && newItems)
  335. InsertMenuItemTextWithCFString( wm,
  336. CFSTR(""), insertAfter, kMenuItemAttrSeparator, 0);
  337. newItems = false;
  338. }
  339. else
  340. {
  341. wxAcceleratorEntry*
  342. entry = wxAcceleratorEntry::Create( item->GetItemLabel() ) ;
  343. MenuItemIndex winListPos = (MenuItemIndex)-1;
  344. OSStatus err = GetIndMenuItemWithCommandID(wm,
  345. wxIdToMacCommand ( item->GetId() ), 1, NULL, &winListPos);
  346. if ( wm && err == menuItemNotFoundErr )
  347. {
  348. // NB: the only way to determine whether or not we should add
  349. // a separator is to know if we've added menu items to the menu
  350. // before the separator.
  351. newItems = true;
  352. UMAInsertMenuItem(wm, wxStripMenuCodes(item->GetItemLabel()) , wxFont::GetDefaultEncoding(), insertAfter, entry);
  353. SetMenuItemCommandID( wm , insertAfter+1 , wxIdToMacCommand ( item->GetId() ) ) ;
  354. SetMenuItemRefCon( wm , insertAfter+1 , (URefCon) item ) ;
  355. }
  356. delete entry ;
  357. }
  358. }
  359. }