]> git.saurik.com Git - wxWidgets.git/blobdiff - src/osx/menu_osx.cpp
changing to allow for 2x ramping up NSApp run
[wxWidgets.git] / src / osx / menu_osx.cpp
index 4ad6fa1fdfc2fe77dc739da4e2222684b692e3e6..2bf5cede9e763d3240b3f7ccce49acd7b63b6c20 100644 (file)
@@ -4,7 +4,6 @@
 // Author:      Stefan Csomor
 // Modified by:
 // Created:     1998-01-01
-// RCS-ID:      $Id$
 // Copyright:   (c) Stefan Csomor
 // Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
@@ -57,7 +56,6 @@ static const int idMenuTitle = -3;
 void wxMenu::Init()
 {
     m_doBreak = false;
-    m_startRadioGroup = -1;
     m_allowRearrange = true;
     m_noEventsMode = false;
 
@@ -89,13 +87,6 @@ void wxMenu::Break()
     // not available on the mac platform
 }
 
-void wxMenu::Attach(wxMenuBarBase *menubar)
-{
-    wxMenuBase::Attach(menubar);
-
-    EndRadioGroup();
-}
-
 void wxMenu::SetAllowRearrange( bool allow )
 {
     m_allowRearrange = allow;
@@ -108,18 +99,20 @@ void wxMenu::SetNoEventsMode( bool noEvents )
 
 // function appends a new item or submenu to the menu
 // append a new item or submenu to the menu
-bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos)
+bool wxMenu::DoInsertOrAppend(wxMenuItem *item, size_t pos)
 {
-    wxASSERT_MSG( pItem != NULL, wxT("can't append NULL item to the menu") );
-    GetPeer()->InsertOrAppend( pItem, pos );
+    wxASSERT_MSG( item != NULL, wxT("can't append NULL item to the menu") );
+    GetPeer()->InsertOrAppend( item, pos );
 
-    if ( pItem->IsSeparator() )
+    bool check = false;
+
+    if ( item->IsSeparator() )
     {
         // nothing to do here
     }
     else
     {
-        wxMenu *pSubMenu = pItem->GetSubMenu() ;
+        wxMenu *pSubMenu = item->GetSubMenu() ;
         if ( pSubMenu != NULL )
         {
             wxASSERT_MSG( pSubMenu->GetHMenu() != NULL , wxT("invalid submenu added"));
@@ -127,77 +120,131 @@ bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos)
 
             pSubMenu->DoRearrange();
         }
-        else
+        else if ( item->IsRadio() )
         {
-            if ( pItem->GetId() == idMenuTitle )
-                pItem->GetMenu()->Enable( idMenuTitle, false );
-        }
-    }
+            // If a previous or next item is a radio button, add this radio
+            // button to the existing radio group. Otherwise start a new one
+            // for it.
+            wxMenuItemList& items = GetMenuItems();
 
-    // if we're already attached to the menubar, we must update it
-    if ( IsAttached() && GetMenuBar()->IsAttached() )
-        GetMenuBar()->Refresh();
-
-    return true ;
-}
+            size_t const
+                posItem = pos == (size_t)-1 ? items.GetCount() - 1 : pos;
 
-void wxMenu::EndRadioGroup()
-{
-    // we're not inside a radio group any longer
-    m_startRadioGroup = -1;
-}
+            wxMenuItemList::compatibility_iterator node = items.Item(posItem);
+            wxCHECK_MSG( node, false, wxS("New item must have been inserted") );
 
-wxMenuItem* wxMenu::DoAppend(wxMenuItem *item)
-{
-    wxCHECK_MSG( item, NULL, wxT("NULL item in wxMenu::DoAppend") );
+            bool foundGroup = false;
+            if ( node->GetPrevious() )
+            {
+                wxMenuItem* const prev = node->GetPrevious()->GetData();
 
-    bool check = false;
+                if ( prev->IsRadio() )
+                {
+                    // This item is in the same group as the preceding one so
+                    // we should use the same starting item, but getting it is
+                    // a bit difficult as we can't query the start radio group
+                    // item for it.
+                    const int groupStart = prev->IsRadioGroupStart()
+                                            ? posItem - 1
+                                            : prev->GetRadioGroupStart();
+                    item->SetRadioGroupStart(groupStart);
+
+                    // We must also account for the new item by incrementing
+                    // the index of the last item in this group.
+                    wxMenuItem* const first = items.Item(groupStart)->GetData();
+                    first->SetRadioGroupEnd(first->GetRadioGroupEnd() + 1);
+
+                    foundGroup = true;
+                }
+            }
 
-    if ( item->GetKind() == wxITEM_RADIO )
-    {
-        int count = GetMenuItemCount();
+            if ( !foundGroup && node->GetNext() )
+            {
+                wxMenuItem* const next = node->GetNext()->GetData();
 
-        if ( m_startRadioGroup == -1 )
-        {
-            // start a new radio group
-            m_startRadioGroup = count;
+                if ( next->IsRadio() )
+                {
+                    // This item is the new starting item of this group as the
+                    // previous item is not a radio item.
+                    wxASSERT_MSG( next->IsRadioGroupStart(),
+                                  wxS("Where is the start of this group?") );
 
-            // for now it has just one element
-            item->SetAsRadioGroupStart();
-            item->SetRadioGroupEnd(m_startRadioGroup);
+                    // The index of the last item of the radio group must be
+                    // incremented to account for the new item.
+                    item->SetAsRadioGroupStart();
+                    item->SetRadioGroupEnd(next->GetRadioGroupEnd() + 1);
 
-            // ensure that we have a checked item in the radio group
-            check = true;
-        }
-        else // extend the current radio group
-        {
-            // we need to update its end item
-            item->SetRadioGroupStart(m_startRadioGroup);
-            wxMenuItemList::compatibility_iterator node = GetMenuItems().Item(m_startRadioGroup);
+                    // And the previous start item is not one any longer.
+                    next->SetAsRadioGroupStart(false);
 
-            if ( node )
-            {
-                node->GetData()->SetRadioGroupEnd(count);
+                    foundGroup = true;
+                }
             }
-            else
+
+            if ( !foundGroup )
             {
-                wxFAIL_MSG( wxT("where is the radio group start item?") );
+                // start a new radio group
+                item->SetAsRadioGroupStart();
+                item->SetRadioGroupEnd(posItem);
+
+                // ensure that we have a checked item in the radio group
+                check = true;
             }
         }
+        else
+        {
+            if ( item->GetId() == idMenuTitle )
+                item->GetMenu()->Enable( idMenuTitle, false );
+        }
     }
-    else // not a radio item
+
+    // We also need to update the indices of radio group start and end we store
+    // in any existing radio items after this item.
+    if ( pos < GetMenuItemCount() - 1 ) // takes into account pos == -1 case
     {
-        EndRadioGroup();
+        for ( wxMenuItemList::compatibility_iterator
+                node = GetMenuItems().Item(pos + 1);
+                node;
+                node = node->GetNext() )
+        {
+            wxMenuItem* const item = node->GetData();
+            if ( item->IsRadio() )
+            {
+                if ( item->IsRadioGroupStart() )
+                {
+                    // If the starting item is after the just inserted one,
+                    // then the end one must be after it too and needs to be
+                    // updated.
+                    item->SetRadioGroupEnd(item->GetRadioGroupEnd() + 1);
+                }
+                else // Not the first radio group item.
+                {
+                    // We need to update the start item index only if it is
+                    // after the just inserted item.
+                    const int groupStart = item->GetRadioGroupStart();
+                    if ( (size_t)groupStart > pos )
+                        item->SetRadioGroupStart(groupStart + 1);
+                }
+            }
+        }
     }
 
-    if ( !wxMenuBase::DoAppend(item) || !DoInsertOrAppend(item) )
-        return NULL;
+    // if we're already attached to the menubar, we must update it
+    if ( IsAttached() && GetMenuBar()->IsAttached() )
+        GetMenuBar()->Refresh();
 
     if ( check )
-        // check the item initially
         item->Check(true);
 
-    return item;
+    return true ;
+}
+
+wxMenuItem* wxMenu::DoAppend(wxMenuItem *item)
+{
+    if (wxMenuBase::DoAppend(item) && DoInsertOrAppend(item) )
+        return item;
+
+    return NULL;
 }
 
 wxMenuItem* wxMenu::DoInsert(size_t pos, wxMenuItem *item)
@@ -210,14 +257,33 @@ wxMenuItem* wxMenu::DoInsert(size_t pos, wxMenuItem *item)
 
 wxMenuItem *wxMenu::DoRemove(wxMenuItem *item)
 {
-    if ( m_startRadioGroup != -1 )
+    if ( item->IsRadio() )
     {
         // Check if we're removing the item starting the radio group
-        if ( GetMenuItems().Item(m_startRadioGroup)->GetData() == item )
+        if ( item->IsRadioGroupStart() )
         {
-            // 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;
+            // Yes, we do, update the next radio group item, if any, to be the
+            // start one now.
+            const int endGroup = item->GetRadioGroupEnd();
+
+            wxMenuItemList::compatibility_iterator
+                node = GetMenuItems().Item(endGroup);
+            wxASSERT_MSG( node, wxS("Should have valid radio group end") );
+
+            while ( node->GetData() != item )
+            {
+                const wxMenuItemList::compatibility_iterator
+                    prevNode = node->GetPrevious();
+                wxMenuItem* const prevItem = prevNode->GetData();
+                if ( prevItem == item )
+                {
+                    prevItem->SetAsRadioGroupStart();
+                    prevItem->SetRadioGroupEnd(endGroup);
+                    break;
+                }
+
+                node = prevNode;
+            }
         }
     }