1 /////////////////////////////////////////////////////////////////////////////
 
   2 // Name:        src/osx/cocoa/menu.mm
 
   3 // Purpose:     wxMenu, wxMenuBar, wxMenuItem
 
   4 // Author:      Stefan Csomor
 
   7 // Copyright:   (c) Stefan Csomor
 
   8 // Licence:     wxWindows licence
 
   9 /////////////////////////////////////////////////////////////////////////////
 
  11 // ============================================================================
 
  12 // headers & declarations
 
  13 // ============================================================================
 
  18 #include "wx/wxprec.h"
 
  25 #include "wx/menuitem.h"
 
  30 #include "wx/osx/private.h"
 
  32 // other standard headers
 
  33 // ----------------------
 
  36 @implementation wxNSMenu
 
  38 - (id) initWithTitle:(NSString*) title
 
  40     self = [super initWithTitle:title];
 
  45 - (void)setImplementation: (wxMenuImpl *) theImplementation
 
  47     impl = theImplementation;
 
  50 - (wxMenuImpl*) implementation
 
  57 // this is more compatible, as it is also called for command-key shortcuts
 
  58 // and under 10.4, we are not getting a 'close' event however...
 
  59 #define wxOSX_USE_NEEDSUPDATE_HOOK 1
 
  61 @interface wxNSMenuController : NSObject wxOSX_10_6_AND_LATER(<NSMenuDelegate>)
 
  65 #if wxOSX_USE_NEEDSUPDATE_HOOK
 
  66 - (void)menuNeedsUpdate:(NSMenu*)smenu;
 
  68 - (void)menuWillOpen:(NSMenu *)menu;
 
  70 - (void)menuDidClose:(NSMenu *)menu;
 
  71 - (void)menu:(NSMenu *)menu willHighlightItem:(NSMenuItem *)item;
 
  75 @implementation wxNSMenuController
 
  83 #if wxOSX_USE_NEEDSUPDATE_HOOK
 
  84 - (void)menuNeedsUpdate:(NSMenu*)smenu
 
  86     wxNSMenu* menu = (wxNSMenu*) smenu;
 
  87     wxMenuImpl* menuimpl = [menu implementation];
 
  90         wxMenu* wxpeer = (wxMenu*) menuimpl->GetWXPeer();
 
  92             wxpeer->HandleMenuOpened();
 
  96 - (void)menuWillOpen:(NSMenu *)smenu
 
  98     wxNSMenu* menu = (wxNSMenu*) smenu;
 
  99     wxMenuImpl* menuimpl = [menu implementation];
 
 102         wxMenu* wxpeer = (wxMenu*) menuimpl->GetWXPeer();
 
 104             wxpeer->HandleMenuOpened();
 
 109 - (void)menuDidClose:(NSMenu *)smenu
 
 111     wxNSMenu* menu = (wxNSMenu*) smenu;
 
 112     wxMenuImpl* menuimpl = [menu implementation];
 
 115         wxMenu* wxpeer = (wxMenu*) menuimpl->GetWXPeer();
 
 117             wxpeer->HandleMenuClosed();
 
 121 - (void)menu:(NSMenu *)smenu willHighlightItem:(NSMenuItem *)item
 
 123     wxNSMenu* menu = (wxNSMenu*) smenu;
 
 124     wxMenuImpl* menuimpl = [menu implementation];
 
 127         wxMenu* wxpeer = (wxMenu*) menuimpl->GetWXPeer();
 
 128         if ( [ item isKindOfClass:[wxNSMenuItem class] ] )
 
 130             wxMenuItemImpl* menuitemimpl = (wxMenuItemImpl*) [ (wxNSMenuItem*) item implementation ];
 
 131             if ( wxpeer && menuitemimpl )
 
 133                 wxpeer->HandleMenuItemHighlighted( menuitemimpl->GetWXPeer() );
 
 141 @interface NSApplication(MissingAppleMenuCall)
 
 142 - (void)setAppleMenu:(NSMenu *)menu;
 
 145 class wxMenuCocoaImpl : public wxMenuImpl
 
 148     wxMenuCocoaImpl( wxMenu* peer , wxNSMenu* menu) : wxMenuImpl(peer), m_osxMenu(menu)
 
 150         static wxNSMenuController* controller = NULL;
 
 151         if ( controller == NULL )
 
 153             controller = [[wxNSMenuController alloc] init];
 
 155         [menu setDelegate:controller];
 
 156         [m_osxMenu setImplementation:this];
 
 163     virtual ~wxMenuCocoaImpl();
 
 165     virtual void InsertOrAppend(wxMenuItem *pItem, size_t pos)
 
 167         NSMenuItem* nsmenuitem = (NSMenuItem*) pItem->GetPeer()->GetHMenuItem();
 
 168         // make sure a call of SetSubMenu is also reflected (occurring after Create)
 
 169         // update the native menu item accordingly
 
 171         if ( pItem->IsSubMenu() )
 
 173             wxMenu* wxsubmenu = pItem->GetSubMenu();
 
 174             WXHMENU nssubmenu = wxsubmenu->GetHMenu();
 
 175             if ( [nsmenuitem submenu] != nssubmenu )
 
 177                 wxsubmenu->GetPeer()->SetTitle( pItem->GetItemLabelText() );
 
 178                 [nsmenuitem setSubmenu:nssubmenu];
 
 182         if ( pos == (size_t) -1 )
 
 183             [m_osxMenu addItem:nsmenuitem ];
 
 185             [m_osxMenu insertItem:nsmenuitem atIndex:pos];
 
 188     virtual void Remove( wxMenuItem *pItem )
 
 190         [m_osxMenu removeItem:(NSMenuItem*) pItem->GetPeer()->GetHMenuItem()];
 
 193     virtual void MakeRoot()
 
 195         [NSApp setMainMenu:m_osxMenu];
 
 196         [NSApp setAppleMenu:[[m_osxMenu itemAtIndex:0] submenu]];
 
 199     virtual void Enable( bool WXUNUSED(enable) )
 
 203     virtual void SetTitle( const wxString& text )
 
 205         wxCFStringRef cfText(text);
 
 206         [m_osxMenu setTitle:cfText.AsNSString()];
 
 209     virtual void PopUp( wxWindow *win, int x, int y )
 
 211         win->ScreenToClient( &x , &y ) ;
 
 212         NSView *view = win->GetPeer()->GetWXWidget();
 
 213         NSRect frame = [view frame];
 
 216         frame.size.width = 1;
 
 217         frame.size.height = 1;
 
 218         NSPopUpButtonCell *popUpButtonCell = [[NSPopUpButtonCell alloc] initTextCell:@"" pullsDown:NO];
 
 219         [popUpButtonCell setAutoenablesItems:NO];
 
 220         [popUpButtonCell setAltersStateOfSelectedItem:NO];
 
 221         [popUpButtonCell setMenu:m_osxMenu];
 
 222         [popUpButtonCell selectItem:nil];
 
 223         [popUpButtonCell performClickWithFrame:frame inView:view];
 
 224         [popUpButtonCell release];
 
 227     WXHMENU GetHMenu() { return m_osxMenu; }
 
 229     static wxMenuImpl* Create( wxMenu* peer, const wxString& title );
 
 230     static wxMenuImpl* CreateRootMenu( wxMenu* peer );
 
 235 wxMenuCocoaImpl::~wxMenuCocoaImpl()
 
 237     [m_osxMenu setDelegate:nil];
 
 238     [m_osxMenu setImplementation:nil];
 
 241         CFRelease(m_osxMenu);
 
 244 wxMenuImpl* wxMenuImpl::Create( wxMenu* peer, const wxString& title )
 
 246     wxCFStringRef cfText( title );
 
 247     wxNSMenu* menu = [[wxNSMenu alloc] initWithTitle:cfText.AsNSString()];
 
 248     wxMenuImpl* c = new wxMenuCocoaImpl( peer, menu );