1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     wxMenu, wxMenuBar, wxMenuItem 
   4 // Author:      Julian Smart 
   5 // Modified by: Vadim Zeitlin 
   8 // Copyright:   (c) Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // =========================================================================== 
  14 // =========================================================================== 
  16 // --------------------------------------------------------------------------- 
  18 // --------------------------------------------------------------------------- 
  20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  21     #pragma implementation "menu.h" 
  24 // For compilers that support precompilation, includes "wx.h". 
  25 #include "wx/wxprec.h" 
  42     #include "wx/ownerdrw.h" 
  45 #include "wx/msw/private.h" 
  58 #include "wx/msw/wince/missing.h" 
  62 // other standard headers 
  65 // ---------------------------------------------------------------------------- 
  67 // ---------------------------------------------------------------------------- 
  69 extern wxMenu 
*wxCurrentPopupMenu
; 
  71 // ---------------------------------------------------------------------------- 
  73 // ---------------------------------------------------------------------------- 
  75 // the (popup) menu title has this special id 
  76 static const int idMenuTitle 
= -3; 
  78 // ---------------------------------------------------------------------------- 
  80 // ---------------------------------------------------------------------------- 
  82 // make the given menu item default 
  83 static void SetDefaultMenuItem(HMENU hmenu
, UINT id
) 
  88     mii
.cbSize 
= sizeof(MENUITEMINFO
); 
  89     mii
.fMask 
= MIIM_STATE
; 
  90     mii
.fState 
= MFS_DEFAULT
; 
  92     if ( !::SetMenuItemInfo(hmenu
, id
, FALSE
, &mii
) ) 
  94         wxLogLastError(wxT("SetMenuItemInfo")); 
 100 UINT 
GetMenuState(HMENU hMenu
, UINT id
, UINT flags
) 
 104     info
.cbSize 
= sizeof(info
); 
 105     info
.fMask 
= MIIM_STATE
; 
 106     if ( !GetMenuItemInfo(hMenu
, id
, flags 
& MF_BYCOMMAND 
? FALSE 
: TRUE
, & info
) ) 
 107         wxLogLastError(wxT("GetMenuItemInfo")); 
 112 // ============================================================================ 
 114 // ============================================================================ 
 116 #include <wx/listimpl.cpp> 
 118 WX_DEFINE_LIST( wxMenuInfoList 
) ; 
 120 #if wxUSE_EXTENDED_RTTI 
 122 WX_DEFINE_FLAGS( wxMenuStyle 
) 
 124 wxBEGIN_FLAGS( wxMenuStyle 
) 
 125     wxFLAGS_MEMBER(wxMENU_TEAROFF
) 
 126 wxEND_FLAGS( wxMenuStyle 
) 
 128 IMPLEMENT_DYNAMIC_CLASS_XTI(wxMenu
, wxEvtHandler
,"wx/menu.h") 
 130 wxCOLLECTION_TYPE_INFO( wxMenuItem 
* , wxMenuItemList 
) ; 
 132 template<> void wxCollectionToVariantArray( wxMenuItemList 
const &theList
, wxxVariantArray 
&value
) 
 134     wxListCollectionToVariantArray
<wxMenuItemList::compatibility_iterator
>( theList 
, value 
) ; 
 137 wxBEGIN_PROPERTIES_TABLE(wxMenu
) 
 138         wxEVENT_PROPERTY( Select 
, wxEVT_COMMAND_MENU_SELECTED 
, wxCommandEvent
) 
 139     wxPROPERTY( Title
, wxString 
, SetTitle
, GetTitle
, wxString(), 0 /*flags*/ , wxT("Helpstring") , wxT("group") ) 
 140     wxREADONLY_PROPERTY_FLAGS( MenuStyle 
, wxMenuStyle 
, long , GetStyle 
, , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style 
 141     wxPROPERTY_COLLECTION( MenuItems 
, wxMenuItemList 
, wxMenuItem
* , Append 
, GetMenuItems 
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) 
 142 wxEND_PROPERTIES_TABLE() 
 144 wxBEGIN_HANDLERS_TABLE(wxMenu
) 
 145 wxEND_HANDLERS_TABLE() 
 147 wxDIRECT_CONSTRUCTOR_2( wxMenu 
, wxString 
, Title 
, long , MenuStyle  
) 
 149 WX_DEFINE_FLAGS( wxMenuBarStyle 
) 
 151 wxBEGIN_FLAGS( wxMenuBarStyle 
) 
 152     wxFLAGS_MEMBER(wxMB_DOCKABLE
) 
 153 wxEND_FLAGS( wxMenuBarStyle 
) 
 155 // the negative id would lead the window (its superclass !) to vetoe streaming out otherwise 
 156 bool wxMenuBarStreamingCallback( const wxObject 
*WXUNUSED(object
), wxWriter 
* , wxPersister 
* , wxxVariantArray 
& ) 
 161 IMPLEMENT_DYNAMIC_CLASS_XTI_CALLBACK(wxMenuBar
, wxWindow 
,"wx/menu.h",wxMenuBarStreamingCallback
) 
 163 IMPLEMENT_DYNAMIC_CLASS_XTI(wxMenuInfo
, wxObject 
, "wx/menu.h" ) 
 165 wxBEGIN_PROPERTIES_TABLE(wxMenuInfo
) 
 166     wxREADONLY_PROPERTY( Menu 
, wxMenu
* , GetMenu 
, , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) 
 167     wxREADONLY_PROPERTY( Title 
, wxString 
, GetTitle 
, wxString() , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) 
 168 wxEND_PROPERTIES_TABLE() 
 170 wxBEGIN_HANDLERS_TABLE(wxMenuInfo
) 
 171 wxEND_HANDLERS_TABLE() 
 173 wxCONSTRUCTOR_2( wxMenuInfo 
, wxMenu
* , Menu 
, wxString 
, Title 
)  
 175 wxCOLLECTION_TYPE_INFO( wxMenuInfo 
* , wxMenuInfoList 
) ; 
 177 template<> void wxCollectionToVariantArray( wxMenuInfoList 
const &theList
, wxxVariantArray 
&value
) 
 179     wxListCollectionToVariantArray
<wxMenuInfoList::compatibility_iterator
>( theList 
, value 
) ; 
 182 wxBEGIN_PROPERTIES_TABLE(wxMenuBar
) 
 183     wxPROPERTY_COLLECTION( MenuInfos 
, wxMenuInfoList 
, wxMenuInfo
* , Append 
, GetMenuInfos 
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) 
 184 wxEND_PROPERTIES_TABLE() 
 186 wxBEGIN_HANDLERS_TABLE(wxMenuBar
) 
 187 wxEND_HANDLERS_TABLE() 
 189 wxCONSTRUCTOR_DUMMY( wxMenuBar 
) 
 192 IMPLEMENT_DYNAMIC_CLASS(wxMenu
, wxEvtHandler
) 
 193 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar
, wxWindow
) 
 194 IMPLEMENT_DYNAMIC_CLASS(wxMenuInfo
, wxObject
) 
 197 const wxMenuInfoList
& wxMenuBar::GetMenuInfos() const 
 199     wxMenuInfoList
* list 
= const_cast< wxMenuInfoList
* >( &m_menuInfos 
) ; 
 200     WX_CLEAR_LIST( wxMenuInfoList 
, *list 
) ; 
 201     for( size_t i 
= 0 ; i 
< GetMenuCount() ; ++i 
) 
 203         wxMenuInfo
* info 
= new wxMenuInfo() ; 
 204         info
->Create( const_cast<wxMenuBar
*>(this)->GetMenu(i
) , GetLabelTop(i
) ) ; 
 205         list
->Append( info 
) ; 
 210 // --------------------------------------------------------------------------- 
 211 // wxMenu construction, adding and removing menu items 
 212 // --------------------------------------------------------------------------- 
 214 // Construct a menu with optional title (then use append) 
 218     m_startRadioGroup 
= -1; 
 221     m_hMenu 
= (WXHMENU
)CreatePopupMenu(); 
 224         wxLogLastError(wxT("CreatePopupMenu")); 
 227     // if we have a title, insert it in the beginning of the menu 
 230         Append(idMenuTitle
, m_title
); 
 235 // The wxWindow destructor will take care of deleting the submenus. 
 238     // we should free Windows resources only if Windows doesn't do it for us 
 239     // which happens if we're attached to a menubar or a submenu of another 
 241     if ( !IsAttached() && !GetParent() ) 
 243         if ( !::DestroyMenu(GetHmenu()) ) 
 245             wxLogLastError(wxT("DestroyMenu")); 
 251     WX_CLEAR_ARRAY(m_accels
); 
 252 #endif // wxUSE_ACCEL 
 257     // this will take effect during the next call to Append() 
 261 void wxMenu::Attach(wxMenuBarBase 
*menubar
) 
 263     wxMenuBase::Attach(menubar
); 
 270 int wxMenu::FindAccel(int id
) const 
 272     size_t n
, count 
= m_accels
.GetCount(); 
 273     for ( n 
= 0; n 
< count
; n
++ ) 
 275         if ( m_accels
[n
]->m_command 
== id 
) 
 282 void wxMenu::UpdateAccel(wxMenuItem 
*item
) 
 284     if ( item
->IsSubMenu() ) 
 286         wxMenu 
*submenu 
= item
->GetSubMenu(); 
 287         wxMenuItemList::compatibility_iterator node 
= submenu
->GetMenuItems().GetFirst(); 
 290             UpdateAccel(node
->GetData()); 
 292             node 
= node
->GetNext(); 
 295     else if ( !item
->IsSeparator() ) 
 297         // find the (new) accel for this item 
 298         wxAcceleratorEntry 
*accel 
= wxGetAccelFromString(item
->GetText()); 
 300             accel
->m_command 
= item
->GetId(); 
 303         int n 
= FindAccel(item
->GetId()); 
 304         if ( n 
== wxNOT_FOUND 
) 
 306             // no old, add new if any 
 310                 return;     // skipping RebuildAccelTable() below 
 314             // replace old with new or just remove the old one if no new 
 319                 m_accels
.RemoveAt(n
); 
 324             GetMenuBar()->RebuildAccelTable(); 
 327     //else: it is a separator, they can't have accels, nothing to do 
 330 #endif // wxUSE_ACCEL 
 332 // append a new item or submenu to the menu 
 333 bool wxMenu::DoInsertOrAppend(wxMenuItem 
*pItem
, size_t pos
) 
 337 #endif // wxUSE_ACCEL 
 341     // if "Break" has just been called, insert a menu break before this item 
 342     // (and don't forget to reset the flag) 
 344         flags 
|= MF_MENUBREAK
; 
 348     if ( pItem
->IsSeparator() ) { 
 349         flags 
|= MF_SEPARATOR
; 
 352     // id is the numeric id for normal menu items and HMENU for submenus as 
 353     // required by ::AppendMenu() API 
 355     wxMenu 
*submenu 
= pItem
->GetSubMenu(); 
 356     if ( submenu 
!= NULL 
) { 
 357         wxASSERT_MSG( submenu
->GetHMenu(), wxT("invalid submenu") ); 
 359         submenu
->SetParent(this); 
 361         id 
= (UINT
)submenu
->GetHMenu(); 
 370     wxString strippedString
; 
 375 #if wxUSE_OWNER_DRAWN 
 376     if ( pItem
->IsOwnerDrawn() ) {  // want to get {Measure|Draw}Item messages? 
 377         // item draws itself, pass pointer to it in data parameter 
 378         flags 
|= MF_OWNERDRAW
; 
 379         pData 
= (LPCTSTR
)pItem
; 
 384         // menu is just a normal string (passed in data parameter) 
 388         strippedString 
= wxStripMenuCodes(pItem
->GetText()); 
 389         pData 
= (wxChar
*)strippedString
.c_str(); 
 391         pData 
= (wxChar
*)pItem
->GetText().c_str(); 
 396     if ( pos 
== (size_t)-1 ) 
 398         ok 
= ::AppendMenu(GetHmenu(), flags
, id
, pData
); 
 402         ok 
= ::InsertMenu(GetHmenu(), pos
, flags 
| MF_BYPOSITION
, id
, pData
); 
 407         wxLogLastError(wxT("Insert or AppendMenu")); 
 412     // if we just appended the title, highlight it 
 414     if ( (int)id 
== idMenuTitle 
) 
 416         // visually select the menu title 
 417         SetDefaultMenuItem(GetHmenu(), id
); 
 421     // if we're already attached to the menubar, we must update it 
 422     if ( IsAttached() && GetMenuBar()->IsAttached() ) 
 424         GetMenuBar()->Refresh(); 
 430 void wxMenu::EndRadioGroup() 
 432     // we're not inside a radio group any longer 
 433     m_startRadioGroup 
= -1; 
 436 wxMenuItem
* wxMenu::DoAppend(wxMenuItem 
*item
) 
 438     wxCHECK_MSG( item
, NULL
, _T("NULL item in wxMenu::DoAppend") ); 
 442     if ( item
->GetKind() == wxITEM_RADIO 
) 
 444         int count 
= GetMenuItemCount(); 
 446         if ( m_startRadioGroup 
== -1 ) 
 448             // start a new radio group 
 449             m_startRadioGroup 
= count
; 
 451             // for now it has just one element 
 452             item
->SetAsRadioGroupStart(); 
 453             item
->SetRadioGroupEnd(m_startRadioGroup
); 
 455             // ensure that we have a checked item in the radio group 
 458         else // extend the current radio group 
 460             // we need to update its end item 
 461             item
->SetRadioGroupStart(m_startRadioGroup
); 
 462             wxMenuItemList::compatibility_iterator node 
= GetMenuItems().Item(m_startRadioGroup
); 
 466                 node
->GetData()->SetRadioGroupEnd(count
); 
 470                 wxFAIL_MSG( _T("where is the radio group start item?") ); 
 474     else // not a radio item 
 479     if ( !wxMenuBase::DoAppend(item
) || !DoInsertOrAppend(item
) ) 
 486         // check the item initially 
 493 wxMenuItem
* wxMenu::DoInsert(size_t pos
, wxMenuItem 
*item
) 
 495     if (wxMenuBase::DoInsert(pos
, item
) && DoInsertOrAppend(item
, pos
)) 
 501 wxMenuItem 
*wxMenu::DoRemove(wxMenuItem 
*item
) 
 503     // we need to find the items position in the child list 
 505     wxMenuItemList::compatibility_iterator node 
= GetMenuItems().GetFirst(); 
 506     for ( pos 
= 0; node
; pos
++ ) 
 508         if ( node
->GetData() == item 
) 
 511         node 
= node
->GetNext(); 
 514     // DoRemove() (unlike Remove) can only be called for existing item! 
 515     wxCHECK_MSG( node
, NULL
, wxT("bug in wxMenu::Remove logic") ); 
 518     // remove the corresponding accel from the accel table 
 519     int n 
= FindAccel(item
->GetId()); 
 520     if ( n 
!= wxNOT_FOUND 
) 
 524         m_accels
.RemoveAt(n
); 
 526     //else: this item doesn't have an accel, nothing to do 
 527 #endif // wxUSE_ACCEL 
 529     // remove the item from the menu 
 530     if ( !::RemoveMenu(GetHmenu(), (UINT
)pos
, MF_BYPOSITION
) ) 
 532         wxLogLastError(wxT("RemoveMenu")); 
 535     if ( IsAttached() && GetMenuBar()->IsAttached() ) 
 537         // otherwise, the chane won't be visible 
 538         GetMenuBar()->Refresh(); 
 541     // and from internal data structures 
 542     return wxMenuBase::DoRemove(item
); 
 545 // --------------------------------------------------------------------------- 
 546 // accelerator helpers 
 547 // --------------------------------------------------------------------------- 
 551 // create the wxAcceleratorEntries for our accels and put them into provided 
 552 // array - return the number of accels we have 
 553 size_t wxMenu::CopyAccels(wxAcceleratorEntry 
*accels
) const 
 555     size_t count 
= GetAccelCount(); 
 556     for ( size_t n 
= 0; n 
< count
; n
++ ) 
 558         *accels
++ = *m_accels
[n
]; 
 564 #endif // wxUSE_ACCEL 
 566 // --------------------------------------------------------------------------- 
 568 // --------------------------------------------------------------------------- 
 570 void wxMenu::SetTitle(const wxString
& label
) 
 572     bool hasNoTitle 
= m_title
.IsEmpty(); 
 575     HMENU hMenu 
= GetHmenu(); 
 579         if ( !label
.IsEmpty() ) 
 581             if ( !::InsertMenu(hMenu
, 0u, MF_BYPOSITION 
| MF_STRING
, 
 582                                (unsigned)idMenuTitle
, m_title
) || 
 583                  !::InsertMenu(hMenu
, 1u, MF_BYPOSITION
, (unsigned)-1, NULL
) ) 
 585                 wxLogLastError(wxT("InsertMenu")); 
 591         if ( label
.IsEmpty() ) 
 593             // remove the title and the separator after it 
 594             if ( !RemoveMenu(hMenu
, 0, MF_BYPOSITION
) || 
 595                  !RemoveMenu(hMenu
, 0, MF_BYPOSITION
) ) 
 597                 wxLogLastError(wxT("RemoveMenu")); 
 606             info
.cbSize 
= sizeof(info
); 
 607             info
.fMask 
= MIIM_TYPE
; 
 608             info
.fType 
= MFT_STRING
; 
 609             info
.cch 
= m_title
.Length(); 
 610             info
.dwTypeData 
= (LPTSTR
) m_title
.c_str(); 
 611             if ( !SetMenuItemInfo(hMenu
, 0, TRUE
, & info
) ) 
 613                 wxLogLastError(wxT("SetMenuItemInfo")); 
 616             if ( !ModifyMenu(hMenu
, 0u, 
 617                              MF_BYPOSITION 
| MF_STRING
, 
 618                              (unsigned)idMenuTitle
, m_title
) ) 
 620                 wxLogLastError(wxT("ModifyMenu")); 
 627     // put the title string in bold face 
 628     if ( !m_title
.IsEmpty() ) 
 630         SetDefaultMenuItem(GetHmenu(), (UINT
)idMenuTitle
); 
 635 // --------------------------------------------------------------------------- 
 637 // --------------------------------------------------------------------------- 
 639 bool wxMenu::MSWCommand(WXUINT 
WXUNUSED(param
), WXWORD id
) 
 641     // ignore commands from the menu title 
 643     // NB: VC++ generates wrong assembler for `if ( id != idMenuTitle )'!! 
 644     if ( id 
!= (WXWORD
)idMenuTitle 
) 
 646         // VZ: previosuly, the command int was set to id too which was quite 
 647         //     useless anyhow (as it could be retrieved using GetId()) and 
 648         //     uncompatible with wxGTK, so now we use the command int instead 
 649         //     to pass the checked status 
 650         UINT menuState 
= ::GetMenuState(GetHmenu(), id
, MF_BYCOMMAND
) ; 
 651         SendEvent(id
, menuState 
& MF_CHECKED
); 
 657 // --------------------------------------------------------------------------- 
 659 // --------------------------------------------------------------------------- 
 661 wxWindow 
*wxMenu::GetWindow() const 
 663     if ( m_invokingWindow 
!= NULL 
) 
 664         return m_invokingWindow
; 
 665     else if ( GetMenuBar() != NULL
) 
 666         return GetMenuBar()->GetFrame(); 
 671 // --------------------------------------------------------------------------- 
 673 // --------------------------------------------------------------------------- 
 675 void wxMenuBar::Init() 
 677     m_eventHandler 
= this; 
 679 #if wxUSE_TOOLBAR && defined(__WXWINCE__) && (_WIN32_WCE < 400 || wxUSE_POCKETPC_UI) 
 682     // Not using a combined wxToolBar/wxMenuBar? then use 
 683     // a commandbar in WinCE .NET just to implement the 
 685 #if defined(__WXWINCE__) && (_WIN32_WCE >= 400 && !wxUSE_POCKETPC_UI) 
 690 wxMenuBar::wxMenuBar() 
 695 wxMenuBar::wxMenuBar( long WXUNUSED(style
) ) 
 700 wxMenuBar::wxMenuBar(int count
, wxMenu 
*menus
[], const wxString titles
[]) 
 704     m_titles
.Alloc(count
); 
 706     for ( int i 
= 0; i 
< count
; i
++ ) 
 708         m_menus
.Append(menus
[i
]); 
 709         m_titles
.Add(titles
[i
]); 
 711         menus
[i
]->Attach(this); 
 715 wxMenuBar::~wxMenuBar() 
 717     // In Windows CE (not .NET), the menubar is always associated 
 718     // with a toolbar, which destroys the menu implicitly. 
 719 #if defined(__WXWINCE__) && (_WIN32_WCE < 400 || wxUSE_POCKETPC_UI) 
 721         GetToolBar()->SetMenuBar(NULL
); 
 723     // we should free Windows resources only if Windows doesn't do it for us 
 724     // which happens if we're attached to a frame 
 725     if (m_hMenu 
&& !IsAttached()) 
 727 #if defined(__WXWINCE__) && (_WIN32_WCE >= 400 && !wxUSE_POCKETPC_UI) 
 728         ::DestroyWindow((HWND
) m_commandBar
); 
 729         m_commandBar 
= (WXHWND
) NULL
; 
 731         ::DestroyMenu((HMENU
)m_hMenu
); 
 733         m_hMenu 
= (WXHMENU
)NULL
; 
 738 // --------------------------------------------------------------------------- 
 740 // --------------------------------------------------------------------------- 
 742 void wxMenuBar::Refresh() 
 744     wxCHECK_RET( IsAttached(), wxT("can't refresh unattached menubar") ); 
 746 #if defined(__WXWINCE__) && (_WIN32_WCE < 400 || wxUSE_POCKETPC_UI) 
 749         CommandBar_DrawMenuBar((HWND
) GetToolBar()->GetHWND(), 0); 
 751 #elif defined(__WXWINCE__) && (_WIN32_WCE >= 400 && !wxUSE_POCKETPC_UI) 
 753         DrawMenuBar((HWND
) m_commandBar
); 
 755     DrawMenuBar(GetHwndOf(GetFrame())); 
 759 WXHMENU 
wxMenuBar::Create() 
 761     // Note: this totally doesn't work on Smartphone, 
 762     // since you have to use resources. 
 763     // We'll have to find another way to add a menu 
 764     // by changing/adding menu items to an existing menu. 
 765 #if defined(__WXWINCE__) && _WIN32_WCE < 400 
 772     HWND hCommandBar 
= (HWND
) GetToolBar()->GetHWND(); 
 773     HMENU hMenu 
= (HMENU
)::SendMessage(hCommandBar
, SHCMBM_GETMENU
, (WPARAM
)0, (LPARAM
)0); 
 777         memset(&tbButton
, 0, sizeof(TBBUTTON
)); 
 778         tbButton
.iBitmap 
= I_IMAGENONE
; 
 779         tbButton
.fsState 
= TBSTATE_ENABLED
; 
 780         tbButton
.fsStyle 
= TBSTYLE_DROPDOWN 
| TBSTYLE_NO_DROPDOWN_ARROW 
| TBSTYLE_AUTOSIZE
; 
 783         for (i 
= 0; i 
< GetMenuCount(); i
++) 
 785             HMENU hPopupMenu 
= (HMENU
) GetMenu(i
)->GetHMenu() ; 
 786             tbButton
.dwData 
= (DWORD
)hPopupMenu
; 
 787             wxString label 
= wxStripMenuCodes(GetLabelTop(i
)); 
 788             tbButton
.iString 
= (int) label
.c_str(); 
 792             tbButton
.idCommand 
= NewControlId(); 
 793             if (!::SendMessage(hCommandBar
, TB_INSERTBUTTON
, position
, (LPARAM
)&tbButton
)) 
 795                 wxLogLastError(wxT("TB_INSERTBUTTON")); 
 799     m_hMenu 
= (WXHMENU
) hMenu
; 
 805     m_hMenu 
= (WXHMENU
)::CreateMenu(); 
 809         wxLogLastError(wxT("CreateMenu")); 
 813         size_t count 
= GetMenuCount(), i
; 
 814         wxMenuList::iterator it
; 
 815         for ( i 
= 0, it 
= m_menus
.begin(); i 
< count
; i
++, it
++ ) 
 817             if ( !::AppendMenu((HMENU
)m_hMenu
, MF_POPUP 
| MF_STRING
, 
 818                                (UINT
)(*it
)->GetHMenu(), 
 821                 wxLogLastError(wxT("AppendMenu")); 
 830 int wxMenuBar::MSWPositionForWxMenu(wxMenu 
*menu
, int wxpos
) 
 833     wxASSERT(menu
->GetHMenu()); 
 836 #if defined(__WXWINCE__) 
 837     int totalMSWItems 
= GetMenuCount(); 
 839     int totalMSWItems 
= GetMenuItemCount((HMENU
)m_hMenu
); 
 842     int i
; // For old C++ compatibility 
 843     for(i
=wxpos
; i
<totalMSWItems
; i
++) 
 845         if(GetSubMenu((HMENU
)m_hMenu
,i
)==(HMENU
)menu
->GetHMenu()) 
 848     for(i
=0; i
<wxpos
; i
++) 
 850         if(GetSubMenu((HMENU
)m_hMenu
,i
)==(HMENU
)menu
->GetHMenu()) 
 857 // --------------------------------------------------------------------------- 
 858 // wxMenuBar functions to work with the top level submenus 
 859 // --------------------------------------------------------------------------- 
 861 // NB: we don't support owner drawn top level items for now, if we do these 
 862 //     functions would have to be changed to use wxMenuItem as well 
 864 void wxMenuBar::EnableTop(size_t pos
, bool enable
) 
 866     wxCHECK_RET( IsAttached(), wxT("doesn't work with unattached menubars") ); 
 867     wxCHECK_RET( pos 
< GetMenuCount(), wxT("invalid menu index") ); 
 869     int flag 
= enable 
? MF_ENABLED 
: MF_GRAYED
; 
 871     EnableMenuItem((HMENU
)m_hMenu
, MSWPositionForWxMenu(GetMenu(pos
),pos
), MF_BYPOSITION 
| flag
); 
 876 void wxMenuBar::SetLabelTop(size_t pos
, const wxString
& label
) 
 878     wxCHECK_RET( pos 
< GetMenuCount(), wxT("invalid menu index") ); 
 880     m_titles
[pos
] = label
; 
 886     //else: have to modify the existing menu 
 888     int mswpos 
= MSWPositionForWxMenu(GetMenu(pos
),pos
); 
 891     UINT flagsOld 
= ::GetMenuState((HMENU
)m_hMenu
, mswpos
, MF_BYPOSITION
); 
 892     if ( flagsOld 
== 0xFFFFFFFF ) 
 894         wxLogLastError(wxT("GetMenuState")); 
 899     if ( flagsOld 
& MF_POPUP 
) 
 901         // HIBYTE contains the number of items in the submenu in this case 
 903         id 
= (UINT
)::GetSubMenu((HMENU
)m_hMenu
, mswpos
); 
 913     info
.cbSize 
= sizeof(info
); 
 914     info
.fMask 
= MIIM_TYPE
; 
 915     info
.fType 
= MFT_STRING
; 
 916     info
.cch 
= label
.Length(); 
 917     info
.dwTypeData 
= (LPTSTR
) label
.c_str(); 
 918     if ( !SetMenuItemInfo(GetHmenu(), id
, TRUE
, & info
) ) 
 920         wxLogLastError(wxT("SetMenuItemInfo")); 
 924     if ( ::ModifyMenu(GetHmenu(), mswpos
, MF_BYPOSITION 
| MF_STRING 
| flagsOld
, 
 925         id
, label
) == (int)0xFFFFFFFF ) 
 927         wxLogLastError(wxT("ModifyMenu")); 
 934 wxString 
wxMenuBar::GetLabelTop(size_t pos
) const 
 936     wxCHECK_MSG( pos 
< GetMenuCount(), wxEmptyString
, 
 937                  wxT("invalid menu index in wxMenuBar::GetLabelTop") ); 
 939     return wxMenuItem::GetLabelFromText(m_titles
[pos
]); 
 942 // --------------------------------------------------------------------------- 
 943 // wxMenuBar construction 
 944 // --------------------------------------------------------------------------- 
 946 wxMenu 
*wxMenuBar::Replace(size_t pos
, wxMenu 
*menu
, const wxString
& title
) 
 948     wxMenu 
*menuOld 
= wxMenuBarBase::Replace(pos
, menu
, title
); 
 952     m_titles
[pos
] = title
; 
 956         int mswpos 
= MSWPositionForWxMenu(menuOld
,pos
); 
 958         // can't use ModifyMenu() because it deletes the submenu it replaces 
 959         if ( !::RemoveMenu(GetHmenu(), (UINT
)mswpos
, MF_BYPOSITION
) ) 
 961             wxLogLastError(wxT("RemoveMenu")); 
 964         if ( !::InsertMenu(GetHmenu(), (UINT
)mswpos
, 
 965                            MF_BYPOSITION 
| MF_POPUP 
| MF_STRING
, 
 966                            (UINT
)GetHmenuOf(menu
), title
) ) 
 968             wxLogLastError(wxT("InsertMenu")); 
 972         if ( menuOld
->HasAccels() || menu
->HasAccels() ) 
 974             // need to rebuild accell table 
 977 #endif // wxUSE_ACCEL 
 985 bool wxMenuBar::Insert(size_t pos
, wxMenu 
*menu
, const wxString
& title
) 
 987     // Find out which MSW item before which we'll be inserting before 
 988     // wxMenuBarBase::Insert is called and GetMenu(pos) is the new menu. 
 989     // If IsAttached() is false this won't be used anyway 
 990     int mswpos 
= (!IsAttached() || (pos 
== m_menus
.GetCount())) 
 991         ?   -1 // append the menu 
 992         :   MSWPositionForWxMenu(GetMenu(pos
),pos
); 
 994     if ( !wxMenuBarBase::Insert(pos
, menu
, title
) ) 
 997     m_titles
.Insert(title
, pos
); 
1001 #if defined(__WXWINCE__) && (_WIN32_WCE < 400 || wxUSE_POCKETPC_UI) 
1005         memset(&tbButton
, 0, sizeof(TBBUTTON
)); 
1006         tbButton
.iBitmap 
= I_IMAGENONE
; 
1007         tbButton
.fsState 
= TBSTATE_ENABLED
; 
1008         tbButton
.fsStyle 
= TBSTYLE_DROPDOWN 
| TBSTYLE_NO_DROPDOWN_ARROW 
| TBSTYLE_AUTOSIZE
; 
1010         HMENU hPopupMenu 
= (HMENU
) menu
->GetHMenu() ; 
1011         tbButton
.dwData 
= (DWORD
)hPopupMenu
; 
1012         wxString label 
= wxStripMenuCodes(title
); 
1013         tbButton
.iString 
= (int) label
.c_str(); 
1015         tbButton
.idCommand 
= NewControlId(); 
1016         if (!::SendMessage((HWND
) GetToolBar()->GetHWND(), TB_INSERTBUTTON
, pos
, (LPARAM
)&tbButton
)) 
1018             wxLogLastError(wxT("TB_INSERTBUTTON")); 
1022         if ( !::InsertMenu(GetHmenu(), mswpos
, 
1023                            MF_BYPOSITION 
| MF_POPUP 
| MF_STRING
, 
1024                            (UINT
)GetHmenuOf(menu
), title
) ) 
1026             wxLogLastError(wxT("InsertMenu")); 
1030         if ( menu
->HasAccels() ) 
1032             // need to rebuild accell table 
1033             RebuildAccelTable(); 
1035 #endif // wxUSE_ACCEL 
1043 bool wxMenuBar::Append(wxMenu 
*menu
, const wxString
& title
) 
1045     WXHMENU submenu 
= menu 
? menu
->GetHMenu() : 0; 
1046     wxCHECK_MSG( submenu
, FALSE
, wxT("can't append invalid menu to menubar") ); 
1048     if ( !wxMenuBarBase::Append(menu
, title
) ) 
1051     m_titles
.Add(title
); 
1055 #if defined(__WXWINCE__) && (_WIN32_WCE < 400 || wxUSE_POCKETPC_UI) 
1059         memset(&tbButton
, 0, sizeof(TBBUTTON
)); 
1060         tbButton
.iBitmap 
= I_IMAGENONE
; 
1061         tbButton
.fsState 
= TBSTATE_ENABLED
; 
1062         tbButton
.fsStyle 
= TBSTYLE_DROPDOWN 
| TBSTYLE_NO_DROPDOWN_ARROW 
| TBSTYLE_AUTOSIZE
; 
1064         size_t pos 
= GetMenuCount(); 
1065         HMENU hPopupMenu 
= (HMENU
) menu
->GetHMenu() ; 
1066         tbButton
.dwData 
= (DWORD
)hPopupMenu
; 
1067         wxString label 
= wxStripMenuCodes(title
); 
1068         tbButton
.iString 
= (int) label
.c_str(); 
1070         tbButton
.idCommand 
= NewControlId(); 
1071         if (!::SendMessage((HWND
) GetToolBar()->GetHWND(), TB_INSERTBUTTON
, pos
, (LPARAM
)&tbButton
)) 
1073             wxLogLastError(wxT("TB_INSERTBUTTON")); 
1077         if ( !::AppendMenu(GetHmenu(), MF_POPUP 
| MF_STRING
, 
1078                            (UINT
)submenu
, title
) ) 
1080             wxLogLastError(wxT("AppendMenu")); 
1085         if ( menu
->HasAccels() ) 
1087             // need to rebuild accelerator table 
1088             RebuildAccelTable(); 
1090 #endif // wxUSE_ACCEL 
1098 wxMenu 
*wxMenuBar::Remove(size_t pos
) 
1100     wxMenu 
*menu 
= wxMenuBarBase::Remove(pos
); 
1106 #if defined(__WXWINCE__) && (_WIN32_WCE < 400 || wxUSE_POCKETPC_UI) 
1109             if (!::SendMessage((HWND
) GetToolBar()->GetHWND(), TB_DELETEBUTTON
, (UINT
) pos
, (LPARAM
) 0)) 
1111                 wxLogLastError(wxT("TB_DELETEBUTTON")); 
1115         if ( !::RemoveMenu(GetHmenu(), (UINT
)MSWPositionForWxMenu(menu
,pos
), MF_BYPOSITION
) ) 
1117             wxLogLastError(wxT("RemoveMenu")); 
1122         if ( menu
->HasAccels() ) 
1124             // need to rebuild accell table 
1125             RebuildAccelTable(); 
1127 #endif // wxUSE_ACCEL 
1133     m_titles
.RemoveAt(pos
); 
1140 void wxMenuBar::RebuildAccelTable() 
1142     // merge the accelerators of all menus into one accel table 
1143     size_t nAccelCount 
= 0; 
1144     size_t i
, count 
= GetMenuCount(); 
1145     wxMenuList::iterator it
; 
1146     for ( i 
= 0, it 
= m_menus
.begin(); i 
< count
; i
++, it
++ ) 
1148         nAccelCount 
+= (*it
)->GetAccelCount(); 
1153         wxAcceleratorEntry 
*accelEntries 
= new wxAcceleratorEntry
[nAccelCount
]; 
1156         for ( i 
= 0, it 
= m_menus
.begin(); i 
< count
; i
++, it
++ ) 
1158             nAccelCount 
+= (*it
)->CopyAccels(&accelEntries
[nAccelCount
]); 
1161         m_accelTable 
= wxAcceleratorTable(nAccelCount
, accelEntries
); 
1163         delete [] accelEntries
; 
1167 #endif // wxUSE_ACCEL 
1169 void wxMenuBar::Attach(wxFrame 
*frame
) 
1171     wxMenuBarBase::Attach(frame
); 
1173 #if defined(__WXWINCE__) && _WIN32_WCE >= 400 
1176 #if wxUSE_POCKETPC_UI 
1179         HWND hCommandBar 
= (HWND
) GetToolBar()->GetHWND(); 
1180         if (!CommandBar_InsertMenubarEx(hCommandBar
, NULL
, (LPTSTR
) m_hMenu
, 0)) 
1182             wxLogLastError(wxT("CommandBar_InsertMenubarEx")); 
1187         m_commandBar 
= (WXHWND
) CommandBar_Create(wxGetInstance(), (HWND
) frame
->GetHWND(), NewControlId()); 
1192             if (!CommandBar_InsertMenubarEx((HWND
) m_commandBar
, NULL
, (LPTSTR
) m_hMenu
, 0)) 
1194                 wxLogLastError(wxT("CommandBar_InsertMenubarEx")); 
1199     // wxUSE_POCKETPC_UI 
1201     // __WXWINCE__ && _WIN32_WCE >= 400 
1204     RebuildAccelTable(); 
1205 #endif // wxUSE_ACCEL 
1208 void wxMenuBar::Detach() 
1210     wxMenuBarBase::Detach(); 
1213 #endif // wxUSE_MENUS