1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/msw/menu.cpp 
   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 // For compilers that support precompilation, includes "wx.h". 
  21 #include "wx/wxprec.h" 
  32     #include "wx/msw/wrapcctl.h" // include <commctrl.h> "properly" 
  40     #include "wx/ownerdrw.h" 
  43 #include "wx/msw/private.h" 
  51 #if (_WIN32_WCE < 400) && !defined(__HANDHELDPC__) 
  55 #include "wx/msw/wince/missing.h" 
  59 // other standard headers 
  62 #if wxUSE_OWNER_DRAWN && defined(MIIM_BITMAP) 
  63     #include "wx/dynlib.h" 
  66 #ifndef MNS_CHECKORBMP 
  67     #define MNS_CHECKORBMP 0x04000000 
  70     #define MIM_STYLE 0x00000010 
  73 // ---------------------------------------------------------------------------- 
  75 // ---------------------------------------------------------------------------- 
  77 // ---------------------------------------------------------------------------- 
  79 // ---------------------------------------------------------------------------- 
  81 // the (popup) menu title has this special id 
  82 static const int idMenuTitle 
= -3; 
  84 // ---------------------------------------------------------------------------- 
  86 // ---------------------------------------------------------------------------- 
  88 // make the given menu item default 
  89 static void SetDefaultMenuItem(HMENU 
WXUNUSED_IN_WINCE(hmenu
), 
  90                                UINT 
WXUNUSED_IN_WINCE(id
)) 
  95     mii
.cbSize 
= sizeof(MENUITEMINFO
); 
  96     mii
.fMask 
= MIIM_STATE
; 
  97     mii
.fState 
= MFS_DEFAULT
; 
  99     if ( !::SetMenuItemInfo(hmenu
, id
, FALSE
, &mii
) ) 
 101         wxLogLastError(wxT("SetMenuItemInfo")); 
 107 UINT 
GetMenuState(HMENU hMenu
, UINT id
, UINT flags
) 
 111     info
.cbSize 
= sizeof(info
); 
 112     info
.fMask 
= MIIM_STATE
; 
 113     // MF_BYCOMMAND is zero so test MF_BYPOSITION 
 114     if ( !::GetMenuItemInfo(hMenu
, id
, flags 
& MF_BYPOSITION 
? TRUE 
: FALSE 
, & info
) ) 
 115         wxLogLastError(wxT("GetMenuItemInfo")); 
 120 // ============================================================================ 
 122 // ============================================================================ 
 124 #include "wx/listimpl.cpp" 
 126 WX_DEFINE_LIST( wxMenuInfoList 
) 
 128 #if wxUSE_EXTENDED_RTTI 
 130 WX_DEFINE_FLAGS( wxMenuStyle 
) 
 132 wxBEGIN_FLAGS( wxMenuStyle 
) 
 133     wxFLAGS_MEMBER(wxMENU_TEAROFF
) 
 134 wxEND_FLAGS( wxMenuStyle 
) 
 136 IMPLEMENT_DYNAMIC_CLASS_XTI(wxMenu
, wxEvtHandler
,"wx/menu.h") 
 138 wxCOLLECTION_TYPE_INFO( wxMenuItem 
* , wxMenuItemList 
) ; 
 140 template<> void wxCollectionToVariantArray( wxMenuItemList 
const &theList
, wxxVariantArray 
&value
) 
 142     wxListCollectionToVariantArray
<wxMenuItemList::compatibility_iterator
>( theList 
, value 
) ; 
 145 wxBEGIN_PROPERTIES_TABLE(wxMenu
) 
 146     wxEVENT_PROPERTY( Select 
, wxEVT_COMMAND_MENU_SELECTED 
, wxCommandEvent
) 
 147     wxPROPERTY( Title
, wxString 
, SetTitle
, GetTitle
, wxString(), 0 /*flags*/ , wxT("Helpstring") , wxT("group") ) 
 148     wxREADONLY_PROPERTY_FLAGS( MenuStyle 
, wxMenuStyle 
, long , GetStyle 
, EMPTY_MACROVALUE 
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style 
 149     wxPROPERTY_COLLECTION( MenuItems 
, wxMenuItemList 
, wxMenuItem
* , Append 
, GetMenuItems 
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) 
 150 wxEND_PROPERTIES_TABLE() 
 152 wxBEGIN_HANDLERS_TABLE(wxMenu
) 
 153 wxEND_HANDLERS_TABLE() 
 155 wxDIRECT_CONSTRUCTOR_2( wxMenu 
, wxString 
, Title 
, long , MenuStyle  
) 
 157 WX_DEFINE_FLAGS( wxMenuBarStyle 
) 
 159 wxBEGIN_FLAGS( wxMenuBarStyle 
) 
 160     wxFLAGS_MEMBER(wxMB_DOCKABLE
) 
 161 wxEND_FLAGS( wxMenuBarStyle 
) 
 163 // the negative id would lead the window (its superclass !) to vetoe streaming out otherwise 
 164 bool wxMenuBarStreamingCallback( const wxObject 
*WXUNUSED(object
), wxWriter 
* , wxPersister 
* , wxxVariantArray 
& ) 
 169 IMPLEMENT_DYNAMIC_CLASS_XTI_CALLBACK(wxMenuBar
, wxWindow 
,"wx/menu.h",wxMenuBarStreamingCallback
) 
 171 IMPLEMENT_DYNAMIC_CLASS_XTI(wxMenuInfo
, wxObject 
, "wx/menu.h" ) 
 173 wxBEGIN_PROPERTIES_TABLE(wxMenuInfo
) 
 174     wxREADONLY_PROPERTY( Menu 
, wxMenu
* , GetMenu 
, EMPTY_MACROVALUE 
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) 
 175     wxREADONLY_PROPERTY( Title 
, wxString 
, GetTitle 
, wxString() , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) 
 176 wxEND_PROPERTIES_TABLE() 
 178 wxBEGIN_HANDLERS_TABLE(wxMenuInfo
) 
 179 wxEND_HANDLERS_TABLE() 
 181 wxCONSTRUCTOR_2( wxMenuInfo 
, wxMenu
* , Menu 
, wxString 
, Title 
) 
 183 wxCOLLECTION_TYPE_INFO( wxMenuInfo 
* , wxMenuInfoList 
) ; 
 185 template<> void wxCollectionToVariantArray( wxMenuInfoList 
const &theList
, wxxVariantArray 
&value
) 
 187     wxListCollectionToVariantArray
<wxMenuInfoList::compatibility_iterator
>( theList 
, value 
) ; 
 190 wxBEGIN_PROPERTIES_TABLE(wxMenuBar
) 
 191     wxPROPERTY_COLLECTION( MenuInfos 
, wxMenuInfoList 
, wxMenuInfo
* , Append 
, GetMenuInfos 
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) 
 192 wxEND_PROPERTIES_TABLE() 
 194 wxBEGIN_HANDLERS_TABLE(wxMenuBar
) 
 195 wxEND_HANDLERS_TABLE() 
 197 wxCONSTRUCTOR_DUMMY( wxMenuBar 
) 
 200 IMPLEMENT_DYNAMIC_CLASS(wxMenu
, wxEvtHandler
) 
 201 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar
, wxWindow
) 
 202 IMPLEMENT_DYNAMIC_CLASS(wxMenuInfo
, wxObject
) 
 205 const wxMenuInfoList
& wxMenuBar::GetMenuInfos() const 
 207     wxMenuInfoList
* list 
= const_cast< wxMenuInfoList
* >( &m_menuInfos 
) ; 
 208     WX_CLEAR_LIST( wxMenuInfoList 
, *list 
) ; 
 209     for( size_t i 
= 0 ; i 
< GetMenuCount() ; ++i 
) 
 211         wxMenuInfo
* info 
= new wxMenuInfo() ; 
 212         info
->Create( const_cast<wxMenuBar
*>(this)->GetMenu(i
) , GetLabelTop(i
) ) ; 
 213         list
->Append( info 
) ; 
 218 // --------------------------------------------------------------------------- 
 219 // wxMenu construction, adding and removing menu items 
 220 // --------------------------------------------------------------------------- 
 222 // Construct a menu with optional title (then use append) 
 226     m_startRadioGroup 
= -1; 
 229     m_hMenu 
= (WXHMENU
)CreatePopupMenu(); 
 232         wxLogLastError(wxT("CreatePopupMenu")); 
 235     // if we have a title, insert it in the beginning of the menu 
 236     if ( !m_title
.empty() ) 
 238         Append(idMenuTitle
, m_title
); 
 243 // The wxWindow destructor will take care of deleting the submenus. 
 246     // we should free Windows resources only if Windows doesn't do it for us 
 247     // which happens if we're attached to a menubar or a submenu of another 
 249     if ( !IsAttached() && !GetParent() ) 
 251         if ( !::DestroyMenu(GetHmenu()) ) 
 253             wxLogLastError(wxT("DestroyMenu")); 
 259     WX_CLEAR_ARRAY(m_accels
); 
 260 #endif // wxUSE_ACCEL 
 265     // this will take effect during the next call to Append() 
 269 void wxMenu::Attach(wxMenuBarBase 
*menubar
) 
 271     wxMenuBase::Attach(menubar
); 
 278 int wxMenu::FindAccel(int id
) const 
 280     size_t n
, count 
= m_accels
.GetCount(); 
 281     for ( n 
= 0; n 
< count
; n
++ ) 
 283         if ( m_accels
[n
]->m_command 
== id 
) 
 290 void wxMenu::UpdateAccel(wxMenuItem 
*item
) 
 292     if ( item
->IsSubMenu() ) 
 294         wxMenu 
*submenu 
= item
->GetSubMenu(); 
 295         wxMenuItemList::compatibility_iterator node 
= submenu
->GetMenuItems().GetFirst(); 
 298             UpdateAccel(node
->GetData()); 
 300             node 
= node
->GetNext(); 
 303     else if ( !item
->IsSeparator() ) 
 305         // recurse upwards: we should only modify m_accels of the top level 
 306         // menus, not of the submenus as wxMenuBar doesn't look at them 
 307         // (alternative and arguable cleaner solution would be to recurse 
 308         // downwards in GetAccelCount() and CopyAccels()) 
 311             GetParent()->UpdateAccel(item
); 
 315         // find the (new) accel for this item 
 316         wxAcceleratorEntry 
*accel 
= wxAcceleratorEntry::Create(item
->GetText()); 
 318             accel
->m_command 
= item
->GetId(); 
 321         int n 
= FindAccel(item
->GetId()); 
 322         if ( n 
== wxNOT_FOUND 
) 
 324             // no old, add new if any 
 328                 return;     // skipping RebuildAccelTable() below 
 332             // replace old with new or just remove the old one if no new 
 337                 m_accels
.RemoveAt(n
); 
 342             GetMenuBar()->RebuildAccelTable(); 
 345     //else: it is a separator, they can't have accels, nothing to do 
 348 #endif // wxUSE_ACCEL 
 350 // append a new item or submenu to the menu 
 351 bool wxMenu::DoInsertOrAppend(wxMenuItem 
*pItem
, size_t pos
) 
 355 #endif // wxUSE_ACCEL 
 359     // if "Break" has just been called, insert a menu break before this item 
 360     // (and don't forget to reset the flag) 
 362         flags 
|= MF_MENUBREAK
; 
 366     if ( pItem
->IsSeparator() ) { 
 367         flags 
|= MF_SEPARATOR
; 
 370     // id is the numeric id for normal menu items and HMENU for submenus as 
 371     // required by ::AppendMenu() API 
 373     wxMenu 
*submenu 
= pItem
->GetSubMenu(); 
 374     if ( submenu 
!= NULL 
) { 
 375         wxASSERT_MSG( submenu
->GetHMenu(), wxT("invalid submenu") ); 
 377         submenu
->SetParent(this); 
 379         id 
= (UINT
)submenu
->GetHMenu(); 
 388     // prepare to insert the item in the menu 
 389     wxString itemText 
= pItem
->GetText(); 
 390     LPCTSTR pData 
= NULL
; 
 391     if ( pos 
== (size_t)-1 ) 
 393         // append at the end (note that the item is already appended to 
 394         // internal data structures) 
 395         pos 
= GetMenuItemCount() - 1; 
 398     // adjust position to account for the title, if any 
 399     if ( !m_title
.empty() ) 
 400         pos 
+= 2; // for the title itself and its separator 
 404     // check if we have something more than a simple text item 
 405 #if wxUSE_OWNER_DRAWN 
 406     if ( pItem
->IsOwnerDrawn() ) 
 408         // is the item owner-drawn just because of the bitmap? 
 409         if ( pItem
->GetBitmap().Ok() && 
 410                 !pItem
->GetTextColour().Ok() && 
 411                     !pItem
->GetBackgroundColour().Ok() && 
 412                         !pItem
->GetFont().Ok() && 
 413                             !pItem
->GetBitmap(true).Ok() ) 
 415             // try to use InsertMenuItem() as it's guaranteed to look correct 
 416             // while our owner-drawn code is not 
 418             // first compile-time check 
 419 #if defined(MIIM_BITMAP) && (_WIN32_WINNT >= 0x0500) 
 420             WinStruct
<MENUITEMINFO
> mii
; 
 422             // now run-time one: MIIM_BITMAP only works under WinME/2000+ 
 423             if ( wxGetWinVersion() >= wxWinVersion_98 
) 
 425                 mii
.fMask 
= MIIM_STRING 
| MIIM_DATA 
| MIIM_BITMAP
; 
 426                 mii
.cch 
= itemText
.length(); 
 427                 mii
.dwTypeData 
= wx_const_cast(wxChar 
*, itemText
.c_str()); 
 429                 if (flags 
& MF_POPUP
) 
 431                     mii
.fMask 
|= MIIM_SUBMENU
; 
 432                     mii
.hSubMenu 
= (HMENU
)pItem
->GetSubMenu()->GetHMenu(); 
 436                     mii
.fMask 
|= MIIM_ID
; 
 440                 // we can't pass HBITMAP directly as hbmpItem for 2 reasons: 
 441                 //  1. we can't draw it with transparency then (this is not 
 442                 //     very important now but would be with themed menu bg) 
 443                 //  2. worse, Windows inverts the bitmap for the selected 
 444                 //     item and this looks downright ugly 
 446                 // so instead draw it ourselves in MSWOnDrawItem() 
 447                 mii
.dwItemData 
= wx_reinterpret_cast(ULONG_PTR
, pItem
); 
 448                 mii
.hbmpItem 
= HBMMENU_CALLBACK
; 
 450                 ok 
= ::InsertMenuItem(GetHmenu(), pos
, TRUE 
/* by pos */, &mii
); 
 453                     wxLogLastError(wxT("InsertMenuItem()")); 
 455                 else // InsertMenuItem() ok 
 457                     // we need to remove the extra indent which is reserved for 
 458                     // the checkboxes by default as it looks ugly unless check 
 459                     // boxes are used together with bitmaps and this is not the 
 461                     WinStruct
<MENUINFO
> mi
; 
 463                     // don't call SetMenuInfo() directly, this would prevent 
 464                     // the app from starting up under Windows 95/NT 4 
 465                     typedef BOOL (WINAPI 
*SetMenuInfo_t
)(HMENU
, MENUINFO 
*); 
 467                     wxDynamicLibrary 
dllUser(_T("user32")); 
 468                     wxDYNLIB_FUNCTION(SetMenuInfo_t
, SetMenuInfo
, dllUser
); 
 469                     if ( pfnSetMenuInfo 
) 
 471                         mi
.fMask 
= MIM_STYLE
; 
 472                         mi
.dwStyle 
= MNS_CHECKORBMP
; 
 473                         if ( !(*pfnSetMenuInfo
)(GetHmenu(), &mi
) ) 
 474                             wxLogLastError(_T("SetMenuInfo(MNS_NOCHECK)")); 
 477                     // tell the item that it's not really owner-drawn but only 
 478                     // needs to draw its bitmap, the rest is done by Windows 
 479                     pItem
->ResetOwnerDrawn(); 
 482 #endif // MIIM_BITMAP 
 487             // item draws itself, pass pointer to it in data parameter 
 488             flags 
|= MF_OWNERDRAW
; 
 489             pData 
= (LPCTSTR
)pItem
; 
 493 #endif // wxUSE_OWNER_DRAWN 
 495         // item is just a normal string (passed in data parameter) 
 499         itemText 
= wxMenuItem::GetLabelFromText(itemText
); 
 502         pData 
= (wxChar
*)itemText
.c_str(); 
 505     // item might have already been inserted by InsertMenuItem() above 
 508         if ( !::InsertMenu(GetHmenu(), pos
, flags 
| MF_BYPOSITION
, id
, pData
) ) 
 510             wxLogLastError(wxT("InsertMenu[Item]()")); 
 517     // if we just appended the title, highlight it 
 518     if ( (int)id 
== idMenuTitle 
) 
 520         // visually select the menu title 
 521         SetDefaultMenuItem(GetHmenu(), id
); 
 524     // if we're already attached to the menubar, we must update it 
 525     if ( IsAttached() && GetMenuBar()->IsAttached() ) 
 527         GetMenuBar()->Refresh(); 
 533 void wxMenu::EndRadioGroup() 
 535     // we're not inside a radio group any longer 
 536     m_startRadioGroup 
= -1; 
 539 wxMenuItem
* wxMenu::DoAppend(wxMenuItem 
*item
) 
 541     wxCHECK_MSG( item
, NULL
, _T("NULL item in wxMenu::DoAppend") ); 
 545     if ( item
->GetKind() == wxITEM_RADIO 
) 
 547         int count 
= GetMenuItemCount(); 
 549         if ( m_startRadioGroup 
== -1 ) 
 551             // start a new radio group 
 552             m_startRadioGroup 
= count
; 
 554             // for now it has just one element 
 555             item
->SetAsRadioGroupStart(); 
 556             item
->SetRadioGroupEnd(m_startRadioGroup
); 
 558             // ensure that we have a checked item in the radio group 
 561         else // extend the current radio group 
 563             // we need to update its end item 
 564             item
->SetRadioGroupStart(m_startRadioGroup
); 
 565             wxMenuItemList::compatibility_iterator node 
= GetMenuItems().Item(m_startRadioGroup
); 
 569                 node
->GetData()->SetRadioGroupEnd(count
); 
 573                 wxFAIL_MSG( _T("where is the radio group start item?") ); 
 577     else // not a radio item 
 582     if ( !wxMenuBase::DoAppend(item
) || !DoInsertOrAppend(item
) ) 
 589         // check the item initially 
 596 wxMenuItem
* wxMenu::DoInsert(size_t pos
, wxMenuItem 
*item
) 
 598     if (wxMenuBase::DoInsert(pos
, item
) && DoInsertOrAppend(item
, pos
)) 
 604 wxMenuItem 
*wxMenu::DoRemove(wxMenuItem 
*item
) 
 606     // we need to find the item's position in the child list 
 608     wxMenuItemList::compatibility_iterator node 
= GetMenuItems().GetFirst(); 
 609     for ( pos 
= 0; node
; pos
++ ) 
 611         if ( node
->GetData() == item 
) 
 614         node 
= node
->GetNext(); 
 617     // DoRemove() (unlike Remove) can only be called for an existing item! 
 618     wxCHECK_MSG( node
, NULL
, wxT("bug in wxMenu::Remove logic") ); 
 621     // remove the corresponding accel from the accel table 
 622     int n 
= FindAccel(item
->GetId()); 
 623     if ( n 
!= wxNOT_FOUND 
) 
 627         m_accels
.RemoveAt(n
); 
 629     //else: this item doesn't have an accel, nothing to do 
 630 #endif // wxUSE_ACCEL 
 632     // remove the item from the menu 
 633     if ( !::RemoveMenu(GetHmenu(), (UINT
)pos
, MF_BYPOSITION
) ) 
 635         wxLogLastError(wxT("RemoveMenu")); 
 638     if ( IsAttached() && GetMenuBar()->IsAttached() ) 
 640         // otherwise, the change won't be visible 
 641         GetMenuBar()->Refresh(); 
 644     // and from internal data structures 
 645     return wxMenuBase::DoRemove(item
); 
 648 // --------------------------------------------------------------------------- 
 649 // accelerator helpers 
 650 // --------------------------------------------------------------------------- 
 654 // create the wxAcceleratorEntries for our accels and put them into the provided 
 655 // array - return the number of accels we have 
 656 size_t wxMenu::CopyAccels(wxAcceleratorEntry 
*accels
) const 
 658     size_t count 
= GetAccelCount(); 
 659     for ( size_t n 
= 0; n 
< count
; n
++ ) 
 661         *accels
++ = *m_accels
[n
]; 
 667 #endif // wxUSE_ACCEL 
 669 // --------------------------------------------------------------------------- 
 671 // --------------------------------------------------------------------------- 
 673 void wxMenu::SetTitle(const wxString
& label
) 
 675     bool hasNoTitle 
= m_title
.empty(); 
 678     HMENU hMenu 
= GetHmenu(); 
 682         if ( !label
.empty() ) 
 684             if ( !::InsertMenu(hMenu
, 0u, MF_BYPOSITION 
| MF_STRING
, 
 685                                (unsigned)idMenuTitle
, m_title
) || 
 686                  !::InsertMenu(hMenu
, 1u, MF_BYPOSITION
, (unsigned)-1, NULL
) ) 
 688                 wxLogLastError(wxT("InsertMenu")); 
 696             // remove the title and the separator after it 
 697             if ( !RemoveMenu(hMenu
, 0, MF_BYPOSITION
) || 
 698                  !RemoveMenu(hMenu
, 0, MF_BYPOSITION
) ) 
 700                 wxLogLastError(wxT("RemoveMenu")); 
 709             info
.cbSize 
= sizeof(info
); 
 710             info
.fMask 
= MIIM_TYPE
; 
 711             info
.fType 
= MFT_STRING
; 
 712             info
.cch 
= m_title
.length(); 
 713             info
.dwTypeData 
= (LPTSTR
) m_title
.c_str(); 
 714             if ( !SetMenuItemInfo(hMenu
, 0, TRUE
, & info
) ) 
 716                 wxLogLastError(wxT("SetMenuItemInfo")); 
 719             if ( !ModifyMenu(hMenu
, 0u, 
 720                              MF_BYPOSITION 
| MF_STRING
, 
 721                              (unsigned)idMenuTitle
, m_title
) ) 
 723                 wxLogLastError(wxT("ModifyMenu")); 
 730     // put the title string in bold face 
 731     if ( !m_title
.empty() ) 
 733         SetDefaultMenuItem(GetHmenu(), (UINT
)idMenuTitle
); 
 738 // --------------------------------------------------------------------------- 
 740 // --------------------------------------------------------------------------- 
 742 bool wxMenu::MSWCommand(WXUINT 
WXUNUSED(param
), WXWORD id
) 
 744     // ignore commands from the menu title 
 745     if ( id 
!= (WXWORD
)idMenuTitle 
) 
 747         // get the checked status of the command: notice that menuState is the 
 748         // old state of the menu, so the test for MF_CHECKED must be inverted 
 749         UINT menuState 
= ::GetMenuState(GetHmenu(), id
, MF_BYCOMMAND
); 
 750         SendEvent(id
, !(menuState 
& MF_CHECKED
)); 
 756 // --------------------------------------------------------------------------- 
 758 // --------------------------------------------------------------------------- 
 760 wxWindow 
*wxMenu::GetWindow() const 
 762     if ( m_invokingWindow 
!= NULL 
) 
 763         return m_invokingWindow
; 
 764     else if ( GetMenuBar() != NULL
) 
 765         return GetMenuBar()->GetFrame(); 
 770 // --------------------------------------------------------------------------- 
 772 // --------------------------------------------------------------------------- 
 774 void wxMenuBar::Init() 
 776     m_eventHandler 
= this; 
 778 #if wxUSE_TOOLBAR && defined(__WXWINCE__) 
 781     // Not using a combined wxToolBar/wxMenuBar? then use 
 782     // a commandbar in WinCE .NET just to implement the 
 784 #if defined(WINCE_WITH_COMMANDBAR) 
 786     m_adornmentsAdded 
= false; 
 790 wxMenuBar::wxMenuBar() 
 795 wxMenuBar::wxMenuBar( long WXUNUSED(style
) ) 
 800 wxMenuBar::wxMenuBar(size_t count
, wxMenu 
*menus
[], const wxString titles
[], long WXUNUSED(style
)) 
 804     m_titles
.Alloc(count
); 
 806     for ( size_t i 
= 0; i 
< count
; i
++ ) 
 808         m_menus
.Append(menus
[i
]); 
 809         m_titles
.Add(titles
[i
]); 
 811         menus
[i
]->Attach(this); 
 815 wxMenuBar::~wxMenuBar() 
 817     // In Windows CE (not .NET), the menubar is always associated 
 818     // with a toolbar, which destroys the menu implicitly. 
 819 #if defined(WINCE_WITHOUT_COMMANDBAR) && defined(__POCKETPC__) 
 822         wxToolMenuBar
* toolMenuBar 
= wxDynamicCast(GetToolBar(), wxToolMenuBar
); 
 824             toolMenuBar
->SetMenuBar(NULL
); 
 827     // we should free Windows resources only if Windows doesn't do it for us 
 828     // which happens if we're attached to a frame 
 829     if (m_hMenu 
&& !IsAttached()) 
 831 #if defined(WINCE_WITH_COMMANDBAR) 
 832         ::DestroyWindow((HWND
) m_commandBar
); 
 833         m_commandBar 
= (WXHWND
) NULL
; 
 835         ::DestroyMenu((HMENU
)m_hMenu
); 
 837         m_hMenu 
= (WXHMENU
)NULL
; 
 842 // --------------------------------------------------------------------------- 
 844 // --------------------------------------------------------------------------- 
 846 void wxMenuBar::Refresh() 
 851     wxCHECK_RET( IsAttached(), wxT("can't refresh unattached menubar") ); 
 853 #if defined(WINCE_WITHOUT_COMMANDBAR) 
 856         CommandBar_DrawMenuBar((HWND
) GetToolBar()->GetHWND(), 0); 
 858 #elif defined(WINCE_WITH_COMMANDBAR) 
 860         DrawMenuBar((HWND
) m_commandBar
); 
 862     DrawMenuBar(GetHwndOf(GetFrame())); 
 866 WXHMENU 
wxMenuBar::Create() 
 868     // Note: this doesn't work at all on Smartphone, 
 869     // since you have to use resources. 
 870     // We'll have to find another way to add a menu 
 871     // by changing/adding menu items to an existing menu. 
 872 #if defined(WINCE_WITHOUT_COMMANDBAR) 
 879     HWND hCommandBar 
= (HWND
) GetToolBar()->GetHWND(); 
 880     HMENU hMenu 
= (HMENU
)::SendMessage(hCommandBar
, SHCMBM_GETMENU
, (WPARAM
)0, (LPARAM
)0); 
 882     // hMenu may be zero on Windows Mobile 5. So add the menus anyway. 
 886         memset(&tbButton
, 0, sizeof(TBBUTTON
)); 
 887         tbButton
.iBitmap 
= I_IMAGENONE
; 
 888         tbButton
.fsState 
= TBSTATE_ENABLED
; 
 889         tbButton
.fsStyle 
= TBSTYLE_DROPDOWN 
| TBSTYLE_NO_DROPDOWN_ARROW 
| TBSTYLE_AUTOSIZE
; 
 892         for (i 
= 0; i 
< GetMenuCount(); i
++) 
 894             HMENU hPopupMenu 
= (HMENU
) GetMenu(i
)->GetHMenu() ; 
 895             tbButton
.dwData 
= (DWORD
)hPopupMenu
; 
 896             wxString label 
= wxStripMenuCodes(GetLabelTop(i
)); 
 897             tbButton
.iString 
= (int) label
.c_str(); 
 901             tbButton
.idCommand 
= NewControlId(); 
 902             if (!::SendMessage(hCommandBar
, TB_INSERTBUTTON
, position
, (LPARAM
)&tbButton
)) 
 904                 wxLogLastError(wxT("TB_INSERTBUTTON")); 
 908     m_hMenu 
= (WXHMENU
) hMenu
; 
 914     m_hMenu 
= (WXHMENU
)::CreateMenu(); 
 918         wxLogLastError(wxT("CreateMenu")); 
 922         size_t count 
= GetMenuCount(), i
; 
 923         wxMenuList::iterator it
; 
 924         for ( i 
= 0, it 
= m_menus
.begin(); i 
< count
; i
++, it
++ ) 
 926             if ( !::AppendMenu((HMENU
)m_hMenu
, MF_POPUP 
| MF_STRING
, 
 927                                (UINT
)(*it
)->GetHMenu(), 
 930                 wxLogLastError(wxT("AppendMenu")); 
 939 int wxMenuBar::MSWPositionForWxMenu(wxMenu 
*menu
, int wxpos
) 
 942     wxASSERT(menu
->GetHMenu()); 
 945 #if defined(__WXWINCE__) 
 946     int totalMSWItems 
= GetMenuCount(); 
 948     int totalMSWItems 
= GetMenuItemCount((HMENU
)m_hMenu
); 
 951     int i
; // For old C++ compatibility 
 952     for(i
=wxpos
; i
<totalMSWItems
; i
++) 
 954         if(GetSubMenu((HMENU
)m_hMenu
,i
)==(HMENU
)menu
->GetHMenu()) 
 957     for(i
=0; i
<wxpos
; i
++) 
 959         if(GetSubMenu((HMENU
)m_hMenu
,i
)==(HMENU
)menu
->GetHMenu()) 
 966 // --------------------------------------------------------------------------- 
 967 // wxMenuBar functions to work with the top level submenus 
 968 // --------------------------------------------------------------------------- 
 970 // NB: we don't support owner drawn top level items for now, if we do these 
 971 //     functions would have to be changed to use wxMenuItem as well 
 973 void wxMenuBar::EnableTop(size_t pos
, bool enable
) 
 975     wxCHECK_RET( IsAttached(), wxT("doesn't work with unattached menubars") ); 
 976     wxCHECK_RET( pos 
< GetMenuCount(), wxT("invalid menu index") ); 
 978     int flag 
= enable 
? MF_ENABLED 
: MF_GRAYED
; 
 980     EnableMenuItem((HMENU
)m_hMenu
, MSWPositionForWxMenu(GetMenu(pos
),pos
), MF_BYPOSITION 
| flag
); 
 985 void wxMenuBar::SetLabelTop(size_t pos
, const wxString
& label
) 
 987     wxCHECK_RET( pos 
< GetMenuCount(), wxT("invalid menu index") ); 
 989     m_titles
[pos
] = label
; 
 995     //else: have to modify the existing menu 
 997     int mswpos 
= MSWPositionForWxMenu(GetMenu(pos
),pos
); 
1000     UINT flagsOld 
= ::GetMenuState((HMENU
)m_hMenu
, mswpos
, MF_BYPOSITION
); 
1001     if ( flagsOld 
== 0xFFFFFFFF ) 
1003         wxLogLastError(wxT("GetMenuState")); 
1008     if ( flagsOld 
& MF_POPUP 
) 
1010         // HIBYTE contains the number of items in the submenu in this case 
1012         id 
= (UINT
)::GetSubMenu((HMENU
)m_hMenu
, mswpos
); 
1022     info
.cbSize 
= sizeof(info
); 
1023     info
.fMask 
= MIIM_TYPE
; 
1024     info
.fType 
= MFT_STRING
; 
1025     info
.cch 
= label
.length(); 
1026     info
.dwTypeData 
= (LPTSTR
) label
.c_str(); 
1027     if ( !SetMenuItemInfo(GetHmenu(), id
, TRUE
, & info
) ) 
1029         wxLogLastError(wxT("SetMenuItemInfo")); 
1033     if ( ::ModifyMenu(GetHmenu(), mswpos
, MF_BYPOSITION 
| MF_STRING 
| flagsOld
, 
1034         id
, label
) == (int)0xFFFFFFFF ) 
1036         wxLogLastError(wxT("ModifyMenu")); 
1043 wxString 
wxMenuBar::GetLabelTop(size_t pos
) const 
1045     wxCHECK_MSG( pos 
< GetMenuCount(), wxEmptyString
, 
1046                  wxT("invalid menu index in wxMenuBar::GetLabelTop") ); 
1048     return wxMenuItem::GetLabelFromText(m_titles
[pos
]); 
1051 // --------------------------------------------------------------------------- 
1052 // wxMenuBar construction 
1053 // --------------------------------------------------------------------------- 
1055 wxMenu 
*wxMenuBar::Replace(size_t pos
, wxMenu 
*menu
, const wxString
& title
) 
1057     wxMenu 
*menuOld 
= wxMenuBarBase::Replace(pos
, menu
, title
); 
1061     m_titles
[pos
] = title
; 
1063 #if defined(WINCE_WITHOUT_COMMANDBAR) 
1069         int mswpos 
= MSWPositionForWxMenu(menuOld
,pos
); 
1071         // can't use ModifyMenu() because it deletes the submenu it replaces 
1072         if ( !::RemoveMenu(GetHmenu(), (UINT
)mswpos
, MF_BYPOSITION
) ) 
1074             wxLogLastError(wxT("RemoveMenu")); 
1077         if ( !::InsertMenu(GetHmenu(), (UINT
)mswpos
, 
1078                            MF_BYPOSITION 
| MF_POPUP 
| MF_STRING
, 
1079                            (UINT
)GetHmenuOf(menu
), title
) ) 
1081             wxLogLastError(wxT("InsertMenu")); 
1085         if ( menuOld
->HasAccels() || menu
->HasAccels() ) 
1087             // need to rebuild accell table 
1088             RebuildAccelTable(); 
1090 #endif // wxUSE_ACCEL 
1099 bool wxMenuBar::Insert(size_t pos
, wxMenu 
*menu
, const wxString
& title
) 
1101     // Find out which MSW item before which we'll be inserting before 
1102     // wxMenuBarBase::Insert is called and GetMenu(pos) is the new menu. 
1103     // If IsAttached() is false this won't be used anyway 
1105 #if defined(WINCE_WITHOUT_COMMANDBAR) 
1111     int mswpos 
= (!isAttached 
|| (pos 
== m_menus
.GetCount())) 
1112         ?   -1 // append the menu 
1113         :   MSWPositionForWxMenu(GetMenu(pos
),pos
); 
1115     if ( !wxMenuBarBase::Insert(pos
, menu
, title
) ) 
1118     m_titles
.Insert(title
, pos
); 
1122 #if defined(WINCE_WITHOUT_COMMANDBAR) 
1126         memset(&tbButton
, 0, sizeof(TBBUTTON
)); 
1127         tbButton
.iBitmap 
= I_IMAGENONE
; 
1128         tbButton
.fsState 
= TBSTATE_ENABLED
; 
1129         tbButton
.fsStyle 
= TBSTYLE_DROPDOWN 
| TBSTYLE_NO_DROPDOWN_ARROW 
| TBSTYLE_AUTOSIZE
; 
1131         HMENU hPopupMenu 
= (HMENU
) menu
->GetHMenu() ; 
1132         tbButton
.dwData 
= (DWORD
)hPopupMenu
; 
1133         wxString label 
= wxStripMenuCodes(title
); 
1134         tbButton
.iString 
= (int) label
.c_str(); 
1136         tbButton
.idCommand 
= NewControlId(); 
1137         if (!::SendMessage((HWND
) GetToolBar()->GetHWND(), TB_INSERTBUTTON
, pos
, (LPARAM
)&tbButton
)) 
1139             wxLogLastError(wxT("TB_INSERTBUTTON")); 
1142         wxUnusedVar(mswpos
); 
1144         if ( !::InsertMenu(GetHmenu(), mswpos
, 
1145                            MF_BYPOSITION 
| MF_POPUP 
| MF_STRING
, 
1146                            (UINT
)GetHmenuOf(menu
), title
) ) 
1148             wxLogLastError(wxT("InsertMenu")); 
1152         if ( menu
->HasAccels() ) 
1154             // need to rebuild accell table 
1155             RebuildAccelTable(); 
1157 #endif // wxUSE_ACCEL 
1166 bool wxMenuBar::Append(wxMenu 
*menu
, const wxString
& title
) 
1168     WXHMENU submenu 
= menu 
? menu
->GetHMenu() : 0; 
1169     wxCHECK_MSG( submenu
, false, wxT("can't append invalid menu to menubar") ); 
1171     if ( !wxMenuBarBase::Append(menu
, title
) ) 
1174     m_titles
.Add(title
); 
1176 #if defined(WINCE_WITHOUT_COMMANDBAR) 
1182 #if defined(WINCE_WITHOUT_COMMANDBAR) 
1186         memset(&tbButton
, 0, sizeof(TBBUTTON
)); 
1187         tbButton
.iBitmap 
= I_IMAGENONE
; 
1188         tbButton
.fsState 
= TBSTATE_ENABLED
; 
1189         tbButton
.fsStyle 
= TBSTYLE_DROPDOWN 
| TBSTYLE_NO_DROPDOWN_ARROW 
| TBSTYLE_AUTOSIZE
; 
1191         size_t pos 
= GetMenuCount(); 
1192         HMENU hPopupMenu 
= (HMENU
) menu
->GetHMenu() ; 
1193         tbButton
.dwData 
= (DWORD
)hPopupMenu
; 
1194         wxString label 
= wxStripMenuCodes(title
); 
1195         tbButton
.iString 
= (int) label
.c_str(); 
1197         tbButton
.idCommand 
= NewControlId(); 
1198         if (!::SendMessage((HWND
) GetToolBar()->GetHWND(), TB_INSERTBUTTON
, pos
, (LPARAM
)&tbButton
)) 
1200             wxLogLastError(wxT("TB_INSERTBUTTON")); 
1204         if ( !::AppendMenu(GetHmenu(), MF_POPUP 
| MF_STRING
, 
1205                            (UINT
)submenu
, title
) ) 
1207             wxLogLastError(wxT("AppendMenu")); 
1212         if ( menu
->HasAccels() ) 
1214             // need to rebuild accelerator table 
1215             RebuildAccelTable(); 
1217 #endif // wxUSE_ACCEL 
1226 wxMenu 
*wxMenuBar::Remove(size_t pos
) 
1228     wxMenu 
*menu 
= wxMenuBarBase::Remove(pos
); 
1232 #if defined(WINCE_WITHOUT_COMMANDBAR) 
1238 #if defined(WINCE_WITHOUT_COMMANDBAR) 
1241             if (!::SendMessage((HWND
) GetToolBar()->GetHWND(), TB_DELETEBUTTON
, (UINT
) pos
, (LPARAM
) 0)) 
1243                 wxLogLastError(wxT("TB_DELETEBUTTON")); 
1247         if ( !::RemoveMenu(GetHmenu(), (UINT
)MSWPositionForWxMenu(menu
,pos
), MF_BYPOSITION
) ) 
1249             wxLogLastError(wxT("RemoveMenu")); 
1254         if ( menu
->HasAccels() ) 
1256             // need to rebuild accell table 
1257             RebuildAccelTable(); 
1259 #endif // wxUSE_ACCEL 
1265     m_titles
.RemoveAt(pos
); 
1272 void wxMenuBar::RebuildAccelTable() 
1274     // merge the accelerators of all menus into one accel table 
1275     size_t nAccelCount 
= 0; 
1276     size_t i
, count 
= GetMenuCount(); 
1277     wxMenuList::iterator it
; 
1278     for ( i 
= 0, it 
= m_menus
.begin(); i 
< count
; i
++, it
++ ) 
1280         nAccelCount 
+= (*it
)->GetAccelCount(); 
1285         wxAcceleratorEntry 
*accelEntries 
= new wxAcceleratorEntry
[nAccelCount
]; 
1288         for ( i 
= 0, it 
= m_menus
.begin(); i 
< count
; i
++, it
++ ) 
1290             nAccelCount 
+= (*it
)->CopyAccels(&accelEntries
[nAccelCount
]); 
1293         m_accelTable 
= wxAcceleratorTable(nAccelCount
, accelEntries
); 
1295         delete [] accelEntries
; 
1299 #endif // wxUSE_ACCEL 
1301 void wxMenuBar::Attach(wxFrame 
*frame
) 
1303     wxMenuBarBase::Attach(frame
); 
1305 #if defined(WINCE_WITH_COMMANDBAR) 
1309         m_commandBar 
= (WXHWND
) CommandBar_Create(wxGetInstance(), (HWND
) frame
->GetHWND(), NewControlId()); 
1314             if (!CommandBar_InsertMenubarEx((HWND
) m_commandBar
, NULL
, (LPTSTR
) m_hMenu
, 0)) 
1316                 wxLogLastError(wxT("CommandBar_InsertMenubarEx")); 
1323     RebuildAccelTable(); 
1324 #endif // wxUSE_ACCEL 
1327 #if defined(WINCE_WITH_COMMANDBAR) 
1328 bool wxMenuBar::AddAdornments(long style
) 
1330     if (m_adornmentsAdded 
|| !m_commandBar
) 
1333     if (style 
& wxCLOSE_BOX
) 
1335         if (!CommandBar_AddAdornments((HWND
) m_commandBar
, 0, 0)) 
1336             wxLogLastError(wxT("CommandBar_AddAdornments")); 
1344 void wxMenuBar::Detach() 
1346     wxMenuBarBase::Detach(); 
1349 #endif // wxUSE_MENUS