]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/menu.cpp
Cured some small doc typos; some WIN16 fixes; transferred DLL WinMain to
[wxWidgets.git] / src / msw / menu.cpp
index 1004cd16e88b54914b3ed19aba29e14b3a365dff..dbf1723befbfd79336bdc0c3a16002f4b9c2acb0 100644 (file)
@@ -9,14 +9,6 @@
 // Licence:    wxWindows license
 /////////////////////////////////////////////////////////////////////////////
 
-
-// ============================================================================
-// headers & declarations
-// ============================================================================
-
-// wxWindows headers
-// -----------------
-
 #ifdef __GNUG__
 #pragma implementation "menu.h"
 #endif
@@ -34,8 +26,8 @@
 #include "wx/utils.h"
 #endif
 
-#if USE_OWNER_DRAWN
-#include "wx/ownerdrw.h"
+#if wxUSE_OWNER_DRAWN
+  #include "wx/ownerdrw.h"
 #endif
 
 #include "wx/msw/private.h"
 // ----------------------
 #include <string.h>
 
+// ----------------------------------------------------------------------------
+// constants
+// ----------------------------------------------------------------------------
+
+// the (popup) menu title has this special id
+static const int idMenuTitle = -2;
+
+// ----------------------------------------------------------------------------
+// wxWindows macros
+// ----------------------------------------------------------------------------
 #if !USE_SHARED_LIBRARY
-IMPLEMENT_DYNAMIC_CLASS(wxMenu, wxWindow)
-IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxWindow)
+  IMPLEMENT_DYNAMIC_CLASS(wxMenu, wxEvtHandler)
+  IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxEvtHandler)
 #endif
 
 // ============================================================================
@@ -71,9 +73,11 @@ wxMenu::wxMenu(const wxString& Title, const wxFunction func)
   m_hMenu = (WXHMENU) CreatePopupMenu();
   m_savehMenu = 0 ;
   m_topLevelMenu = this;
+  m_clientData = (void*) NULL;
+
   if (m_title != "")
   {
-    Append(-2, m_title) ;
+    Append(idMenuTitle, m_title) ;
     AppendSeparator() ;
   }
 
@@ -81,7 +85,7 @@ wxMenu::wxMenu(const wxString& Title, const wxFunction func)
 }
 
 // The wxWindow destructor will take care of deleting the submenus.
-wxMenu::~wxMenu(void)
+wxMenu::~wxMenu()
 {
   if (m_hMenu)
     DestroyMenu((HMENU) m_hMenu);
@@ -131,7 +135,7 @@ wxMenu::~wxMenu(void)
 */
 }
 
-void wxMenu::Break(void)
+void wxMenu::Break()
 {
   m_doBreak = TRUE ;
 }
@@ -139,7 +143,7 @@ void wxMenu::Break(void)
 // function appends a new item or submenu to the menu
 void wxMenu::Append(wxMenuItem *pItem)
 {
-  wxCHECK( pItem != NULL );
+  wxCHECK_RET( pItem != NULL, "can't append NULL item to the menu" );
 
   m_menuItems.Append(pItem);
 
@@ -158,7 +162,7 @@ void wxMenu::Append(wxMenuItem *pItem)
   UINT id;
   wxMenu *SubMenu = pItem->GetSubMenu();
   if ( SubMenu != NULL ) {
-    wxASSERT( SubMenu->m_hMenu != NULL );
+    wxASSERT( SubMenu->m_hMenu != (WXHMENU) NULL );
 
     id = (UINT)SubMenu->m_hMenu;
 
@@ -174,9 +178,8 @@ void wxMenu::Append(wxMenuItem *pItem)
   }
 
   LPCSTR pData;
-  wxString name("");
 
-#if USE_OWNER_DRAWN
+#if wxUSE_OWNER_DRAWN
   if ( pItem->IsOwnerDrawn() ) {  // want to get {Measure|Draw}Item messages?
     // item draws itself, pass pointer to it in data parameter
     flags |= MF_OWNERDRAW;
@@ -187,27 +190,25 @@ void wxMenu::Append(wxMenuItem *pItem)
   {
     // menu is just a normal string (passed in data parameter)
     flags |= MF_STRING;
-    name = pItem->GetName();
-    pData = (const char*) name;
+    pData = pItem->GetName();
   }
 
-  // VZ: what does this magic -2 mean? I just copied the code but have no idea
-  //     about what it does... ###
-  if ( pItem->GetId() == -2 ) {
-    flags |= MF_DISABLED | MF_GRAYED;
+  // visually select the menu title
+  if ( id == idMenuTitle )
+  {
+    // TODO use SetMenuItemInfo(MFS_DEFAULT) to put it in bold face
   }
 
   HMENU hMenu = (HMENU)((m_hMenu == 0) ? m_savehMenu : m_hMenu);
-
   if ( !AppendMenu(hMenu, flags, id, pData) )
   {
-    // wxLogLastError("AppendMenu");
+    wxLogLastError("AppendMenu");
   }
 
   m_noItems++;
 }
 
-void wxMenu::AppendSeparator(void)
+void wxMenu::AppendSeparator()
 {
   Append(new wxMenuItem(this, ID_SEPARATOR));
 }
@@ -230,10 +231,10 @@ void wxMenu::Append(int Id, const wxString& label,
 void wxMenu::Delete(int id)
 {
   wxNode *node;
-  wxMenuItem *item;
   int pos;
   HMENU menu;
 
+  wxMenuItem *item = NULL;
   for (pos = 0, node = m_menuItems.First(); node; node = node->Next(), pos++) {
         item = (wxMenuItem *)node->Data();
         if (item->GetId() == id)
@@ -269,7 +270,7 @@ void wxMenu::Delete(int id)
 void wxMenu::Enable(int Id, bool Flag)
 {
   wxMenuItem *item = FindItemForId(Id);
-  wxCHECK( item != NULL );
+  wxCHECK_RET( item != NULL, "can't enable non-existing menu item" );
 
   item->Enable(Flag);
 }
@@ -277,7 +278,7 @@ void wxMenu::Enable(int Id, bool Flag)
 bool wxMenu::Enabled(int Id) const
 {
   wxMenuItem *item = FindItemForId(Id);
-  wxCHECK_RET( item != NULL, FALSE );
+  wxCHECK( item != NULL, FALSE );
 
   return item->IsEnabled();
 }
@@ -285,7 +286,7 @@ bool wxMenu::Enabled(int Id) const
 void wxMenu::Check(int Id, bool Flag)
 {
   wxMenuItem *item = FindItemForId(Id);
-  wxCHECK( item != NULL );
+  wxCHECK_RET( item != NULL, "can't get status of non-existing menu item" );
 
   item->Check(Flag);
 }
@@ -293,25 +294,71 @@ void wxMenu::Check(int Id, bool Flag)
 bool wxMenu::Checked(int Id) const
 {
   wxMenuItem *item = FindItemForId(Id);
-  wxCHECK_RET( item != NULL, FALSE );
+  wxCHECK( item != NULL, FALSE );
 
   return item->IsChecked();
 }
 
 void wxMenu::SetTitle(const wxString& label)
 {
-  m_title = label ;
-  if (m_hMenu)
-    ModifyMenu((HMENU)m_hMenu, 0,
-             MF_BYPOSITION | MF_STRING | MF_DISABLED,
-             (UINT)-2, (const char *)m_title);
-  else if (m_savehMenu)
-    ModifyMenu((HMENU)m_savehMenu, 0,
-             MF_BYPOSITION | MF_STRING | MF_DISABLED,
-             (UINT)-2, (const char *)m_title);
+  bool hasNoTitle = m_title.IsEmpty();
+  m_title = label;
+
+  HMENU hMenu = (HMENU)((m_hMenu == 0) ? m_savehMenu : m_hMenu);
+
+  if ( hasNoTitle )
+  {
+    if ( !label.IsEmpty() )
+    {
+      if ( !InsertMenu(hMenu, 0u, MF_BYPOSITION | MF_STRING,
+                       (unsigned)idMenuTitle, m_title) ||
+           !InsertMenu(hMenu, 1u, MF_BYPOSITION, (unsigned)-1, NULL) )
+      {
+        wxLogLastError("InsertMenu");
+      }
+    }
+  }
+  else
+  {
+    if ( label.IsEmpty() )
+    {
+      // remove the title and the separator after it
+      if ( !RemoveMenu(hMenu, 0, MF_BYPOSITION) ||
+           !RemoveMenu(hMenu, 0, MF_BYPOSITION) )
+      {
+        wxLogLastError("RemoveMenu");
+      }
+    }
+    else
+    {
+      // modify the title
+      if ( !ModifyMenu(hMenu, 0u,
+                       MF_BYPOSITION | MF_STRING,
+                       (unsigned)idMenuTitle, m_title) )
+      {
+        wxLogLastError("ModifyMenu");
+      }
+    }
+  }
+
+#ifndef __WIN16__
+  // put the title string in bold face
+  if ( !m_title.IsEmpty() )
+  {
+    MENUITEMINFO mii;
+    mii.cbSize = sizeof(mii);
+    mii.fMask = MIIM_STATE;
+    mii.fState = MFS_DEFAULT;
+
+    if ( !SetMenuItemInfo(hMenu, (unsigned)idMenuTitle, FALSE, &mii) )
+    {
+      wxLogLastError("SetMenuItemInfo");
+    }
+  }
+#endif
 }
 
-const wxString& wxMenu::GetTitle() const
+const wxString wxMenu::GetTitle() const
 {
    return m_title;
 }
@@ -356,8 +403,9 @@ void wxMenu::SetLabel(int Id, const wxString& label)
   item->SetName(label);
 }
 
-wxString wxMenu::GetLabel(int Id) const
+wxString wxMenu::GetLabel(int id) const
 {
+/*
   static char tmp[128] ;
   int len;
   if (m_hMenu)
@@ -368,16 +416,30 @@ wxString wxMenu::GetLabel(int Id) const
     len = 0 ;
   tmp[len] = '\0' ;
   return wxString(tmp) ;
+
+*/
+    wxMenuItem *pItem = FindItemForId(id) ;
+    if (pItem)
+        return pItem->GetName() ;
+    else
+        return wxEmptyString;
 }
 
-bool wxMenu::MSWCommand(const WXUINT WXUNUSED(param), const WXWORD id)
+bool wxMenu::MSWCommand(WXUINT WXUNUSED(param), WXWORD id)
 {
-  wxCommandEvent event(wxEVENT_TYPE_MENU_COMMAND);
-  event.SetEventObject( this );
-  event.SetId( id );
-  event.SetInt( id );
-  ProcessCommand(event);
-  return TRUE;
+    // ignore commands from the menu title
+
+    // NB: VC++ generates wrong assembler for `if ( id != idMenuTitle )'!!
+    if ( id != (WXWORD)idMenuTitle )
+    {
+        wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED);
+        event.SetEventObject( this );
+        event.SetId( id );
+        event.SetInt( id );
+        ProcessCommand(event);
+    }
+
+    return TRUE;
 }
 
 // Finds the item id matching the given string, -1 if not found.
@@ -407,7 +469,7 @@ int wxMenu::FindItem (const wxString& itemString) const
   return -1;
 }
 
-wxMenuItem *wxMenu::FindItemForId(const int itemId, wxMenu ** itemMenu) const
+wxMenuItem *wxMenu::FindItemForId(int itemId, wxMenu ** itemMenu) const
 {
   if (itemMenu)
     *itemMenu = NULL;
@@ -435,18 +497,20 @@ wxMenuItem *wxMenu::FindItemForId(const int itemId, wxMenu ** itemMenu) const
   return NULL;
 }
 
-void wxMenu::SetHelpString(const int itemId, const wxString& helpString)
+void wxMenu::SetHelpString(int itemId, const wxString& helpString)
 {
   wxMenuItem *item = FindItemForId (itemId);
   if (item)
     item->SetHelp(helpString);
 }
 
-wxString wxMenu::GetHelpString (const int itemId) const
+wxString wxMenu::GetHelpString (int itemId) const
 {
   wxMenuItem *item = FindItemForId (itemId);
-  wxString str("");
-  return (item == NULL) ? str : item->GetHelp();
+  if (item)
+    return item->GetHelp();
+  else
+    return wxEmptyString;
 }
 
 void wxMenu::ProcessCommand(wxCommandEvent & event)
@@ -456,7 +520,7 @@ void wxMenu::ProcessCommand(wxCommandEvent & event)
   // Try a callback
   if (m_callback)
   {
-      (void) (*(m_callback)) (*this, event);
+      (void)(*(m_callback))(*this, event);
       processed = TRUE;
   }
 
@@ -469,13 +533,14 @@ void wxMenu::ProcessCommand(wxCommandEvent & event)
   // Try the window the menu was popped up from (and up
   // through the hierarchy)
   if ( !processed && GetInvokingWindow())
-    processed = GetInvokingWindow()->ProcessEvent(event);
+    processed = GetInvokingWindow()->GetEventHandler()->ProcessEvent(event);
 }
 
 extern wxMenu *wxCurrentPopupMenu;
-bool wxWindow::PopupMenu(wxMenu *menu, const int x, const int y)
+bool wxWindow::PopupMenu(wxMenu *menu, int x, int y)
 {
   menu->SetInvokingWindow(this);
+  menu->UpdateUI();
 
   HWND hWnd = (HWND) GetHWND();
   HMENU hMenu = (HMENU)menu->m_hMenu;
@@ -494,7 +559,7 @@ bool wxWindow::PopupMenu(wxMenu *menu, const int x, const int y)
 }
 
 // Menu Bar
-wxMenuBar::wxMenuBar(void)
+wxMenuBar::wxMenuBar()
 {
   m_eventHandler = this;
 
@@ -505,7 +570,7 @@ wxMenuBar::wxMenuBar(void)
   m_hMenu = 0;
 }
 
-wxMenuBar::wxMenuBar(const int N, wxMenu *Menus[], const wxString Titles[])
+wxMenuBar::wxMenuBar(int N, wxMenu *Menus[], const wxString Titles[])
 {
   m_eventHandler = this;
   m_menuCount = N;
@@ -521,7 +586,7 @@ wxMenuBar::wxMenuBar(const int N, wxMenu *Menus[], const wxString Titles[])
   m_hMenu = 0;
 }
 
-wxMenuBar::~wxMenuBar(void)
+wxMenuBar::~wxMenuBar()
 {
   // In fact, don't want menu to be destroyed before MDI
   // shuffling has taken place. Let it be destroyed
@@ -562,7 +627,7 @@ wxMenuBar::~wxMenuBar(void)
 
 // Must only be used AFTER menu has been attached to frame,
 // otherwise use individual menus to enable/disable items
-void wxMenuBar::Enable(const int Id, const bool Flag)
+void wxMenuBar::Enable(int Id, bool Flag)
 {
   int ms_flag;
   if (Flag)
@@ -582,7 +647,7 @@ void wxMenuBar::Enable(const int Id, const bool Flag)
 
 }
 
-void wxMenuBar::EnableTop(const int pos, const bool flag)
+void wxMenuBar::EnableTop(int pos, bool flag)
 {
   int ms_flag;
   if (flag)
@@ -596,7 +661,7 @@ void wxMenuBar::EnableTop(const int pos, const bool flag)
 
 // Must only be used AFTER menu has been attached to frame,
 // otherwise use individual menus
-void wxMenuBar::Check(const int Id, const bool Flag)
+void wxMenuBar::Check(int Id, bool Flag)
 {
   wxMenu *itemMenu = NULL;
   wxMenuItem *item = FindItemForId(Id, &itemMenu) ;
@@ -619,14 +684,14 @@ void wxMenuBar::Check(const int Id, const bool Flag)
 //  CheckMenuItem((HMENU)m_hMenu, Id, MF_BYCOMMAND | ms_flag);
 }
 
-bool wxMenuBar::Checked(const int Id) const
+bool wxMenuBar::Checked(int Id) const
 {
   wxMenu *itemMenu = NULL;
   wxMenuItem *item = FindItemForId(Id, &itemMenu) ;
   if (!item)
     return FALSE;
 
-  int Flag ;
+  int Flag = 0;
 
   if (itemMenu->m_hMenu)
     Flag=GetMenuState((HMENU)itemMenu->m_hMenu, Id, MF_BYCOMMAND) ;
@@ -641,7 +706,7 @@ bool wxMenuBar::Checked(const int Id) const
     return FALSE ;
 }
 
-bool wxMenuBar::Enabled(const int Id) const
+bool wxMenuBar::Enabled(int Id) const
 {
   wxMenu *itemMenu = NULL;
   wxMenuItem *item = FindItemForId(Id, &itemMenu) ;
@@ -662,7 +727,7 @@ bool wxMenuBar::Enabled(const int Id) const
 }
 
 
-void wxMenuBar::SetLabel(const int Id, const wxString& label)
+void wxMenuBar::SetLabel(int Id, const wxString& label)
 {
   wxMenu *itemMenu = NULL;
   wxMenuItem *item = FindItemForId(Id, &itemMenu) ;
@@ -682,7 +747,7 @@ void wxMenuBar::SetLabel(const int Id, const wxString& label)
   }
 }
 
-wxString wxMenuBar::GetLabel(const int Id) const
+wxString wxMenuBar::GetLabel(int Id) const
 {
   wxMenu *itemMenu = NULL;
   wxMenuItem *item = FindItemForId(Id, &itemMenu) ;
@@ -706,7 +771,7 @@ wxString wxMenuBar::GetLabel(const int Id) const
   return wxString(tmp) ;
 }
 
-void wxMenuBar::SetLabelTop(const int pos, const wxString& label)
+void wxMenuBar::SetLabelTop(int pos, const wxString& label)
 {
   UINT was_flag = GetMenuState((HMENU)m_hMenu,pos,MF_BYPOSITION) ;
   if (was_flag&MF_POPUP)
@@ -719,7 +784,7 @@ void wxMenuBar::SetLabelTop(const int pos, const wxString& label)
     ModifyMenu((HMENU)m_hMenu,pos,MF_BYPOSITION|MF_STRING|was_flag,pos,(const char *)label) ;
 }
 
-wxString wxMenuBar::GetLabelTop(const int pos) const
+wxString wxMenuBar::GetLabelTop(int pos) const
 {
   static char tmp[128] ;
   int len = GetMenuString((HMENU)m_hMenu,pos,tmp,127,MF_BYPOSITION) ;
@@ -727,7 +792,7 @@ wxString wxMenuBar::GetLabelTop(const int pos) const
   return wxString(tmp);
 }
 
-bool wxMenuBar::OnDelete(wxMenu *a_menu, const int pos)
+bool wxMenuBar::OnDelete(wxMenu *a_menu, int pos)
 {
   if (!m_menuBarFrame)
         return TRUE;
@@ -796,7 +861,7 @@ void wxMenuBar::Append (wxMenu * menu, const wxString& title)
   ((wxMenu *)menu)->SetParent(this);
 }
 
-void wxMenuBar::Delete(wxMenu * menu, const int i)
+void wxMenuBar::Delete(wxMenu * menu, int i)
 {
   int j;
   int ii = (int) i;
@@ -843,7 +908,7 @@ int wxMenuBar::FindMenuItem (const wxString& menuString, const wxString& itemStr
   return -1;
 }
 
-wxMenuItem *wxMenuBar::FindItemForId (const int Id, wxMenu ** itemMenu) const
+wxMenuItem *wxMenuBar::FindItemForId (int Id, wxMenu ** itemMenu) const
 {
   if (itemMenu)
     *itemMenu = NULL;
@@ -851,12 +916,15 @@ wxMenuItem *wxMenuBar::FindItemForId (const int Id, wxMenu ** itemMenu) const
   wxMenuItem *item = NULL;
   int i;
   for (i = 0; i < m_menuCount; i++)
-    if ((item = m_menus[i]->FindItemForId (Id, itemMenu)))
+  {
+    item = m_menus[i]->FindItemForId (Id, itemMenu);
+    if (item)
       return item;
+  }
   return NULL;
 }
 
-void wxMenuBar::SetHelpString (const int Id, const wxString& helpString)
+void wxMenuBar::SetHelpString (int Id, const wxString& helpString)
 {
   int i;
   for (i = 0; i < m_menuCount; i++)
@@ -869,7 +937,7 @@ void wxMenuBar::SetHelpString (const int Id, const wxString& helpString)
     }
 }
 
-wxString wxMenuBar::GetHelpString (const int Id) const
+wxString wxMenuBar::GetHelpString (int Id) const
 {
   int i;
   for (i = 0; i < m_menuCount; i++)
@@ -899,3 +967,42 @@ WXHMENU wxMenu::GetHMenu() const
   return 0;
 }
 
+// Update a menu and all submenus recursively.
+// source is the object that has the update event handlers
+// defined for it. If NULL, the menu or associated window
+// will be used.
+void wxMenu::UpdateUI(wxEvtHandler* source)
+{
+  if (!source && GetInvokingWindow())
+    source = GetInvokingWindow()->GetEventHandler();
+  if (!source)
+    source = GetEventHandler();
+  if (!source)
+    source = this;
+
+  wxNode* node = GetItems().First();
+  while (node)
+  {
+    wxMenuItem* item = (wxMenuItem*) node->Data();
+    if ( !item->IsSeparator() )
+    {
+      wxWindowID id = item->GetId();
+      wxUpdateUIEvent event(id);
+      event.SetEventObject( source );
+
+      if (source->ProcessEvent(event))
+      {
+        if (event.GetSetText())
+          SetLabel(id, event.GetText());
+        if (event.GetSetChecked())
+          Check(id, event.GetChecked());
+        if (event.GetSetEnabled())
+          Enable(id, event.GetEnabled());
+      }
+
+      if (item->GetSubMenu())
+        item->GetSubMenu()->UpdateUI(source);
+    }
+    node = node->Next();
+  }
+}