PageRenderTime 27ms CodeModel.GetById 34ms RepoModel.GetById 1ms app.codeStats 0ms

/Externals/wxWidgets3/src/osx/carbon/menu.cpp

https://bitbucket.org/delroth/dolphin-llvm-dsp
C++ | 437 lines | 328 code | 61 blank | 48 comment | 58 complexity | b595511d8a341cb07d9ab508f8a1bd56 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: menu.cpp 70298 2012-01-08 14:52:59Z VZ $
  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.IsOk() )
  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 , MenuRef oldMenu , SInt16 menuId)
  163. : wxMenuImpl(peer), m_osxMenu(menu), m_oldMenuRef(oldMenu), m_menuId(menuId)
  164. {
  165. }
  166. virtual ~wxMenuCarbonImpl();
  167. virtual void InsertOrAppend(wxMenuItem *pItem, size_t pos)
  168. {
  169. // MacOS counts menu items from 1 and inserts after, therefore having the
  170. // same effect as wx 0 based and inserting before, we must correct pos
  171. // after however for updates to be correct
  172. MenuItemIndex index = pos;
  173. if ( pos == (size_t) -1 )
  174. index = CountMenuItems(m_osxMenu);
  175. if ( pItem->IsSeparator() )
  176. {
  177. InsertMenuItemTextWithCFString( m_osxMenu, CFSTR(""), index, kMenuItemAttrSeparator, 0);
  178. // now switch to the Carbon 1 based counting
  179. index += 1 ;
  180. }
  181. else
  182. {
  183. InsertMenuItemTextWithCFString( m_osxMenu, CFSTR("placeholder"), index, 0, 0 );
  184. // now switch to the Carbon 1 based counting
  185. index += 1 ;
  186. if ( pItem->IsSubMenu() )
  187. {
  188. MenuRef submenu = pItem->GetSubMenu()->GetHMenu();
  189. SetMenuItemHierarchicalMenu(m_osxMenu, index, submenu);
  190. // carbon is using the title of the submenu, eg in the menubar
  191. SetMenuTitleWithCFString(submenu, wxCFStringRef(pItem->GetItemLabelText()));
  192. }
  193. else
  194. {
  195. SetMenuItemCommandID( m_osxMenu, index , wxIdToMacCommand(pItem->GetId()) ) ;
  196. }
  197. }
  198. wxMenuItemCarbonImpl* impl = (wxMenuItemCarbonImpl*) pItem->GetPeer();
  199. impl->AttachToParent( m_osxMenu, index );
  200. // only now can all settings be updated correctly
  201. pItem->UpdateItemText();
  202. pItem->UpdateItemStatus();
  203. pItem->UpdateItemBitmap();
  204. }
  205. virtual void Remove( wxMenuItem *pItem )
  206. {
  207. wxMenuItemCarbonImpl* impl = (wxMenuItemCarbonImpl*) pItem->GetPeer();
  208. if ( impl )
  209. {
  210. MenuItemIndex i = impl->FindMenuItemIndex();
  211. if ( i > 0 )
  212. {
  213. DeleteMenuItem(m_osxMenu , i);
  214. impl->AttachToParent( NULL, 0 );
  215. }
  216. }
  217. }
  218. virtual void MakeRoot()
  219. {
  220. SetRootMenu( m_osxMenu );
  221. }
  222. virtual void SetTitle( const wxString& text )
  223. {
  224. SetMenuTitleWithCFString(m_osxMenu, wxCFStringRef(text));
  225. }
  226. WXHMENU GetHMenu() { return m_osxMenu; }
  227. virtual void PopUp( wxWindow *WXUNUSED(win), int x, int y )
  228. {
  229. long menuResult = ::PopUpMenuSelect(m_osxMenu, y, x, 0) ;
  230. if ( HiWord(menuResult) != 0 )
  231. {
  232. MenuCommand macid;
  233. GetMenuItemCommandID( GetMenuHandle(HiWord(menuResult)) , LoWord(menuResult) , &macid );
  234. int id = wxMacCommandToId( macid );
  235. wxMenuItem* item = NULL ;
  236. wxMenu* realmenu ;
  237. item = m_peer->FindItem( id, &realmenu ) ;
  238. if ( item )
  239. {
  240. m_peer->HandleCommandProcess(item, NULL );
  241. }
  242. }
  243. }
  244. static wxMenuImpl* Create( wxMenu* peer, const wxString& title );
  245. static wxMenuImpl* CreateRootMenu( wxMenu* peer );
  246. protected :
  247. wxCFRef<MenuRef> m_osxMenu;
  248. MenuRef m_oldMenuRef;
  249. SInt16 m_menuId;
  250. } ;
  251. // static const short kwxMacAppleMenuId = 1 ;
  252. // Find an item given the Macintosh Menu Reference
  253. WX_DECLARE_HASH_MAP(WXHMENU, wxMenu*, wxPointerHash, wxPointerEqual, MacMenuMap);
  254. static MacMenuMap wxWinMacMenuList;
  255. wxMenu *wxFindMenuFromMacMenu(WXHMENU inMenuRef)
  256. {
  257. MacMenuMap::iterator node = wxWinMacMenuList.find(inMenuRef);
  258. return (node == wxWinMacMenuList.end()) ? NULL : node->second;
  259. }
  260. void wxAssociateMenuWithMacMenu(WXHMENU inMenuRef, wxMenu *menu) ;
  261. void wxAssociateMenuWithMacMenu(WXHMENU inMenuRef, wxMenu *menu)
  262. {
  263. // adding NULL MenuRef is (first) surely a result of an error and
  264. // (secondly) breaks menu command processing
  265. wxCHECK_RET( inMenuRef != (WXHMENU) NULL, wxT("attempt to add a NULL MenuRef to menu list") );
  266. wxWinMacMenuList[inMenuRef] = menu;
  267. }
  268. void wxRemoveMacMenuAssociation(wxMenu *menu) ;
  269. void wxRemoveMacMenuAssociation(wxMenu *menu)
  270. {
  271. // iterate over all the elements in the class
  272. MacMenuMap::iterator it;
  273. for ( it = wxWinMacMenuList.begin(); it != wxWinMacMenuList.end(); ++it )
  274. {
  275. if ( it->second == menu )
  276. {
  277. wxWinMacMenuList.erase(it);
  278. break;
  279. }
  280. }
  281. }
  282. wxMenuCarbonImpl::~wxMenuCarbonImpl()
  283. {
  284. wxRemoveMacMenuAssociation( GetWXPeer() );
  285. // restore previous menu
  286. m_osxMenu.reset();
  287. if ( m_menuId > 0 )
  288. MacDeleteMenu(m_menuId);
  289. if ( m_oldMenuRef )
  290. MacInsertMenu(m_oldMenuRef, -1);
  291. }
  292. wxMenuImpl* wxMenuImpl::Create( wxMenu* peer, const wxString& title )
  293. {
  294. // create the menu
  295. static SInt16 s_macNextMenuId = 3;
  296. SInt16 menuId = s_macNextMenuId++;
  297. // save existing menu in case we're embedding into an application
  298. // or sharing outside UI elements.
  299. WXHMENU oldMenu = GetMenuHandle(menuId);
  300. if ( oldMenu )
  301. MacDeleteMenu(menuId);
  302. WXHMENU menu = NULL;
  303. CreateNewMenu( menuId , 0 , &menu ) ;
  304. if ( !menu )
  305. {
  306. wxLogLastError(wxT("CreateNewMenu failed"));
  307. if ( oldMenu )
  308. MacInsertMenu(oldMenu, -1);
  309. return NULL;
  310. }
  311. wxMenuImpl* c = new wxMenuCarbonImpl( peer, menu, oldMenu, menuId );
  312. c->SetTitle(title);
  313. wxAssociateMenuWithMacMenu( menu , peer ) ;
  314. return c;
  315. }
  316. //
  317. //
  318. //
  319. wxMenuItemCarbonImpl::~wxMenuItemCarbonImpl()
  320. {
  321. }
  322. wxMenuItemImpl* wxMenuItemImpl::Create( wxMenuItem* peer,
  323. wxMenu * WXUNUSED(pParentMenu),
  324. int WXUNUSED(id),
  325. const wxString& WXUNUSED(text),
  326. wxAcceleratorEntry *WXUNUSED(entry),
  327. const wxString& WXUNUSED(strHelp),
  328. wxItemKind WXUNUSED(kind),
  329. wxMenu *WXUNUSED(pSubMenu) )
  330. {
  331. wxMenuItemImpl* c = NULL;
  332. c = new wxMenuItemCarbonImpl( peer );
  333. return c;
  334. }
  335. void wxInsertMenuItemsInMenu(wxMenu* menu, MenuRef wm, MenuItemIndex insertAfter)
  336. {
  337. wxMenuItemList::compatibility_iterator node;
  338. wxMenuItem *item;
  339. wxMenu *subMenu = NULL ;
  340. bool newItems = false;
  341. for (node = menu->GetMenuItems().GetFirst(); node; node = node->GetNext())
  342. {
  343. item = (wxMenuItem *)node->GetData();
  344. subMenu = item->GetSubMenu() ;
  345. if (subMenu)
  346. {
  347. wxInsertMenuItemsInMenu(subMenu, (MenuRef)subMenu->GetHMenu(), 0);
  348. }
  349. if ( item->IsSeparator() )
  350. {
  351. if ( wm && newItems)
  352. InsertMenuItemTextWithCFString( wm,
  353. CFSTR(""), insertAfter, kMenuItemAttrSeparator, 0);
  354. newItems = false;
  355. }
  356. else
  357. {
  358. wxAcceleratorEntry*
  359. entry = wxAcceleratorEntry::Create( item->GetItemLabel() ) ;
  360. MenuItemIndex winListPos = (MenuItemIndex)-1;
  361. OSStatus err = GetIndMenuItemWithCommandID(wm,
  362. wxIdToMacCommand ( item->GetId() ), 1, NULL, &winListPos);
  363. if ( wm && err == menuItemNotFoundErr )
  364. {
  365. // NB: the only way to determine whether or not we should add
  366. // a separator is to know if we've added menu items to the menu
  367. // before the separator.
  368. newItems = true;
  369. UMAInsertMenuItem(wm, wxStripMenuCodes(item->GetItemLabel()) , wxFont::GetDefaultEncoding(), insertAfter, entry);
  370. SetMenuItemCommandID( wm , insertAfter+1 , wxIdToMacCommand ( item->GetId() ) ) ;
  371. SetMenuItemRefCon( wm , insertAfter+1 , (URefCon) item ) ;
  372. }
  373. delete entry ;
  374. }
  375. }
  376. }