]> git.saurik.com Git - wxWidgets.git/blobdiff - src/osx/menu_osx.cpp
Support using GetTextExtent() with empty string to get descent in wxOSX.
[wxWidgets.git] / src / osx / menu_osx.cpp
index 54b2d6aa917ce85e11ad8ea1ac9a7912b865b223..4ad6fa1fdfc2fe77dc739da4e2222684b692e3e6 100644 (file)
@@ -43,7 +43,7 @@ wxMenuImpl::~wxMenuImpl()
 {
 }
 
-// the (popup) menu title has this special id
+// the (popup) menu title has this special menuid
 static const int idMenuTitle = -3;
 
 // ============================================================================
@@ -111,7 +111,7 @@ void wxMenu::SetNoEventsMode( bool noEvents )
 bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos)
 {
     wxASSERT_MSG( pItem != NULL, wxT("can't append NULL item to the menu") );
-    m_peer->InsertOrAppend( pItem, pos );
+    GetPeer()->InsertOrAppend( pItem, pos );
 
     if ( pItem->IsSeparator() )
     {
@@ -210,6 +210,17 @@ wxMenuItem* wxMenu::DoInsert(size_t pos, wxMenuItem *item)
 
 wxMenuItem *wxMenu::DoRemove(wxMenuItem *item)
 {
+    if ( m_startRadioGroup != -1 )
+    {
+        // Check if we're removing the item starting the radio group
+        if ( GetMenuItems().Item(m_startRadioGroup)->GetData() == item )
+        {
+            // Yes, we do, so reset its index as the next item added shouldn't
+            // count as part of the same radio group anyhow.
+            m_startRadioGroup = -1;
+        }
+    }
+
 /*
     // we need to find the items position in the child list
     size_t pos;
@@ -228,7 +239,7 @@ wxMenuItem *wxMenu::DoRemove(wxMenuItem *item)
 
     wxOSXMenuRemoveItem(m_hMenu , pos );
     */
-    m_peer->Remove( item );
+    GetPeer()->Remove( item );
     // and from internal data structures
     return wxMenuBase::DoRemove(item);
 }
@@ -236,7 +247,7 @@ wxMenuItem *wxMenu::DoRemove(wxMenuItem *item)
 void wxMenu::SetTitle(const wxString& label)
 {
     m_title = label ;
-    m_peer->SetTitle( wxStripMenuCodes( label ) );
+    GetPeer()->SetTitle( wxStripMenuCodes( label ) );
 }
 
 bool wxMenu::ProcessCommand(wxCommandEvent & event)
@@ -337,8 +348,8 @@ void wxMenu::DoRearrange()
 
 bool wxMenu::HandleCommandUpdateStatus( wxMenuItem* item, wxWindow* senderWindow )
 {
-    int id = item ? item->GetId() : 0;
-    wxUpdateUIEvent event(id);
+    int menuid = item ? item->GetId() : 0;
+    wxUpdateUIEvent event(menuid);
     event.SetEventObject( this );
 
     bool processed = false;
@@ -368,11 +379,11 @@ bool wxMenu::HandleCommandUpdateStatus( wxMenuItem* item, wxWindow* senderWindow
     {
         // if anything changed, update the changed attribute
         if (event.GetSetText())
-            SetLabel(id, event.GetText());
+            SetLabel(menuid, event.GetText());
         if (event.GetSetChecked())
-            Check(id, event.GetChecked());
+            Check(menuid, event.GetChecked());
         if (event.GetSetEnabled())
-            Enable(id, event.GetEnabled());
+            Enable(menuid, event.GetEnabled());
     }
     else
     {
@@ -381,11 +392,11 @@ bool wxMenu::HandleCommandUpdateStatus( wxMenuItem* item, wxWindow* senderWindow
         // always reset them ourselves
         UInt32 cmd = 0;
 
-        if ( id == wxApp::s_macExitMenuItemId )
+        if ( menuid == wxApp::s_macExitMenuItemId )
         {
             cmd = kHICommandQuit;
         }
-        else if (id == wxApp::s_macPreferencesMenuItemId )
+        else if (menuid == wxApp::s_macPreferencesMenuItemId )
         {
             cmd = kHICommandPreferences;
         }
@@ -406,19 +417,19 @@ bool wxMenu::HandleCommandUpdateStatus( wxMenuItem* item, wxWindow* senderWindow
 
 bool wxMenu::HandleCommandProcess( wxMenuItem* item, wxWindow* senderWindow )
 {
-    int id = item ? item->GetId() : 0;
+    int menuid = item ? item->GetId() : 0;
     bool processed = false;
     if (item->IsCheckable())
         item->Check( !item->IsChecked() ) ;
 
-    if ( SendEvent( id , item->IsCheckable() ? item->IsChecked() : -1 ) )
+    if ( SendEvent( menuid , item->IsCheckable() ? item->IsChecked() : -1 ) )
         processed = true ;
     else
     {
         if ( senderWindow != NULL )
         {
-            wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED , id);
-            event.SetEventObject(senderWindow);
+            wxCommandEvent event(wxEVT_MENU , menuid);
+            event.SetEventObject(this);
             event.SetInt(item->IsCheckable() ? item->IsChecked() : -1);
 
             if ( senderWindow->HandleWindowEvent(event) )
@@ -436,21 +447,30 @@ bool wxMenu::HandleCommandProcess( wxMenuItem* item, wxWindow* senderWindow )
 
 void wxMenu::HandleMenuItemHighlighted( wxMenuItem* item )
 {
-    int id = item ? item->GetId() : 0;
-    wxMenuEvent wxevent(wxEVT_MENU_HIGHLIGHT, id, this);
+    int menuid = item ? item->GetId() : 0;
+    wxMenuEvent wxevent(wxEVT_MENU_HIGHLIGHT, menuid, this);
     DoHandleMenuEvent( wxevent );
 }
 
-void wxMenu::HandleMenuOpened()
+void wxMenu::DoHandleMenuOpenedOrClosed(wxEventType evtType)
 {
-    wxMenuEvent wxevent(wxEVT_MENU_OPEN, 0, this);
+    // Popup menu being currently shown or NULL, defined in wincmn.cpp.
+    extern wxMenu *wxCurrentPopupMenu;
+
+    // Set the id to allow wxMenuEvent::IsPopup() to work correctly.
+    int menuid = this == wxCurrentPopupMenu ? wxID_ANY : 0;
+    wxMenuEvent wxevent(evtType, menuid, this);
     DoHandleMenuEvent( wxevent );
 }
 
+void wxMenu::HandleMenuOpened()
+{
+    DoHandleMenuOpenedOrClosed(wxEVT_MENU_OPEN);
+}
+
 void wxMenu::HandleMenuClosed()
 {
-    wxMenuEvent wxevent(wxEVT_MENU_CLOSE, 0, this);
-    DoHandleMenuEvent( wxevent );
+    DoHandleMenuOpenedOrClosed(wxEVT_MENU_CLOSE);
 }
 
 bool wxMenu::DoHandleMenuEvent(wxEvent& wxevent)
@@ -497,8 +517,37 @@ wxMenuBar* wxMenuBar::s_macCommonMenuBar = NULL ;
 bool     wxMenuBar::s_macAutoWindowMenu = true ;
 WXHMENU  wxMenuBar::s_macWindowMenuHandle = NULL ;
 
+
+wxMenu* emptyMenuBar = NULL;
+
+const int firstMenuPos = 1; // to account for the 0th application menu on mac
+
 void wxMenuBar::Init()
 {
+    if ( emptyMenuBar == NULL )
+    {
+        emptyMenuBar = new wxMenu();
+        
+        wxMenu* appleMenu = new wxMenu();
+        appleMenu->SetAllowRearrange(false);
+#if !wxOSX_USE_CARBON
+        // standard menu items, handled in wxMenu::HandleCommandProcess(), see above:
+        wxString hideLabel;
+        hideLabel = wxString::Format(_("Hide %s"), wxTheApp ? wxTheApp->GetAppDisplayName() : _("Application"));
+        appleMenu->Append( wxID_OSX_HIDE, hideLabel + "\tCtrl+H" );
+        appleMenu->Append( wxID_OSX_HIDEOTHERS, _("Hide Others")+"\tAlt+Ctrl+H" );
+        appleMenu->Append( wxID_OSX_SHOWALL, _("Show All") );
+        appleMenu->AppendSeparator();
+        
+        // Do always add "Quit" item unconditionally however, it can't be disabled.
+        wxString quitLabel;
+        quitLabel = wxString::Format(_("Quit %s"), wxTheApp ? wxTheApp->GetAppDisplayName() : _("Application"));
+        appleMenu->Append( wxApp::s_macExitMenuItemId, quitLabel + "\tCtrl+Q" );
+#endif // !wxOSX_USE_CARBON
+
+        emptyMenuBar->AppendSubMenu(appleMenu, "\x14") ;
+    }
+    
     m_eventHandler = this;
     m_menuBarFrame = NULL;
     m_rootMenu = new wxMenu();
@@ -530,21 +579,17 @@ void wxMenuBar::Init()
     }
 
     // standard menu items, handled in wxMenu::HandleCommandProcess(), see above:
-    wxString hideLabel(_("Hide"));
-    if ( wxTheApp )
-        hideLabel << ' ' << wxTheApp->GetAppDisplayName();
-    hideLabel << "\tCtrl+H";
-    m_appleMenu->Append( wxID_OSX_HIDE, hideLabel );    
+    wxString hideLabel;
+    hideLabel = wxString::Format(_("Hide %s"), wxTheApp ? wxTheApp->GetAppDisplayName() : _("Application"));
+    m_appleMenu->Append( wxID_OSX_HIDE, hideLabel + "\tCtrl+H" );    
     m_appleMenu->Append( wxID_OSX_HIDEOTHERS, _("Hide Others")+"\tAlt+Ctrl+H" );    
     m_appleMenu->Append( wxID_OSX_SHOWALL, _("Show All") );    
     m_appleMenu->AppendSeparator();
     
     // Do always add "Quit" item unconditionally however, it can't be disabled.
-    wxString quitLabel(_("Quit"));
-    if ( wxTheApp )
-        quitLabel << ' ' << wxTheApp->GetAppDisplayName();
-    quitLabel << "\tCtrl+Q";
-    m_appleMenu->Append( wxApp::s_macExitMenuItemId, quitLabel );
+    wxString quitLabel;
+    quitLabel = wxString::Format(_("Quit %s"), wxTheApp ? wxTheApp->GetAppDisplayName() : _("Application"));
+    m_appleMenu->Append( wxApp::s_macExitMenuItemId, quitLabel + "\tCtrl+Q" );
 #endif // !wxOSX_USE_CARBON
 
     m_rootMenu->AppendSubMenu(m_appleMenu, "\x14") ;
@@ -580,8 +625,16 @@ wxMenuBar::~wxMenuBar()
 
     if (s_macInstalledMenuBar == this)
     {
+        emptyMenuBar->GetPeer()->MakeRoot();
         s_macInstalledMenuBar = NULL;
     }
+    wxDELETE( m_rootMenu );
+    // apple menu is a submenu, therefore we don't have to delete it
+    m_appleMenu = NULL;
+
+    // deleting the root menu also removes all its wxMenu* submenus, therefore
+    // we must avoid double deleting them in the superclass destructor
+    m_menus.clear();
 }
 
 void wxMenuBar::Refresh(bool WXUNUSED(eraseBackground), const wxRect *WXUNUSED(rect))
@@ -598,13 +651,12 @@ void wxMenuBar::MacInstallMenuBar()
     
     // hide items in the apple menu that don't exist in the wx menubar
     
-    int id = 0;
     wxMenuItem* appleItem = NULL;
     wxMenuItem* wxItem = NULL;
 
-    id = wxApp::s_macAboutMenuItemId;
-    appleItem = m_appleMenu->FindItem(id);
-    wxItem = FindItem(id);
+    int menuid = wxApp::s_macAboutMenuItemId;
+    appleItem = m_appleMenu->FindItem(menuid);
+    wxItem = FindItem(menuid);
     if ( appleItem != NULL )
     {
         if ( wxItem == NULL )
@@ -613,9 +665,9 @@ void wxMenuBar::MacInstallMenuBar()
             appleItem->SetItemLabel(wxItem->GetItemLabel());
     }
     
-    id = wxApp::s_macPreferencesMenuItemId;
-    appleItem = m_appleMenu->FindItem(id);
-    wxItem = FindItem(id);
+    menuid = wxApp::s_macPreferencesMenuItemId;
+    appleItem = m_appleMenu->FindItem(menuid);
+    wxItem = FindItem(menuid);
     if ( appleItem != NULL )
     {
         if ( wxItem == NULL )
@@ -627,26 +679,6 @@ void wxMenuBar::MacInstallMenuBar()
         
 #if 0
 
-    MenuBarHandle menubar = NULL ;
-
-    menubar = NewHandleClear( 6 /* sizeof( MenuBarHeader ) */ ) ;
-
-    ::SetMenuBar( menubar ) ;
-    DisposeMenuBar( menubar ) ;
-    MenuHandle appleMenu = NULL ;
-
-    verify_noerr( CreateNewMenu( kwxMacAppleMenuId , 0 , &appleMenu ) ) ;
-    verify_noerr( SetMenuTitleWithCFString( appleMenu , CFSTR( "\x14" ) ) );
-
-    // Add About/Preferences separator only on OS X
-    // KH/RN: Separator is always present on 10.3 but not on 10.2
-    // However, the change from 10.2 to 10.3 suggests it is preferred
-    InsertMenuItemTextWithCFString( appleMenu,
-                CFSTR(""), 0, kMenuItemAttrSeparator, 0);
-    InsertMenuItemTextWithCFString( appleMenu,
-                CFSTR("About..."), 0, 0, 0);
-    MacInsertMenu( appleMenu , 0 ) ;
-
     // if we have a mac help menu, clean it up before adding new items
     MenuHandle helpMenuHandle ;
     MenuItemIndex firstUserHelpMenuItem ;
@@ -826,11 +858,22 @@ void wxMenuBar::EnableTop(size_t pos, bool enable)
 {
     wxCHECK_RET( IsAttached(), wxT("doesn't work with unattached menubars") );
 
-    m_rootMenu->FindItemByPosition( pos )->Enable(enable);
+    m_rootMenu->FindItemByPosition(pos+firstMenuPos)->Enable(enable);
 
     Refresh();
 }
 
+bool wxMenuBar::IsEnabledTop(size_t pos) const
+{
+    wxCHECK_MSG( IsAttached(), true,
+                 wxT("doesn't work with unattached menubars") );
+
+    wxMenuItem* const item = m_rootMenu->FindItemByPosition(pos+firstMenuPos);
+    wxCHECK_MSG( item, false, wxT("invalid menu index") );
+
+    return item->IsEnabled();
+}
+
 bool wxMenuBar::Enable(bool enable)
 {
     wxCHECK_MSG( IsAttached(), false, wxT("doesn't work with unattached menubars") );
@@ -861,8 +904,6 @@ wxString wxMenuBar::GetMenuLabel(size_t pos) const
 // wxMenuBar construction
 // ---------------------------------------------------------------------------
 
-const int firstMenuPos = 1; // to account for the 0th application menu on mac
-
 wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title)
 {
     wxMenu *menuOld = wxMenuBarBase::Replace(pos, menu, title);
@@ -882,6 +923,7 @@ bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title)
         return false;
 
     m_rootMenu->Insert( pos+firstMenuPos, wxMenuItem::New( m_rootMenu, wxID_ANY, title, "", wxITEM_NORMAL, menu ) );
+    menu->SetTitle(title);
 
     return true;
 }