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"
55 #ifndef TBSTYLE_NO_DROPDOWN_ARROW
56 #define TBSTYLE_NO_DROPDOWN_ARROW 0x0080
61 // other standard headers
64 // ----------------------------------------------------------------------------
66 // ----------------------------------------------------------------------------
68 extern wxMenu
*wxCurrentPopupMenu
;
70 // ----------------------------------------------------------------------------
72 // ----------------------------------------------------------------------------
74 // the (popup) menu title has this special id
75 static const int idMenuTitle
= -2;
77 // ----------------------------------------------------------------------------
79 // ----------------------------------------------------------------------------
81 // make the given menu item default
82 static void SetDefaultMenuItem(HMENU hmenu
, UINT id
)
87 mii
.cbSize
= sizeof(MENUITEMINFO
);
88 mii
.fMask
= MIIM_STATE
;
89 mii
.fState
= MFS_DEFAULT
;
91 if ( !::SetMenuItemInfo(hmenu
, id
, FALSE
, &mii
) )
93 wxLogLastError(wxT("SetMenuItemInfo"));
99 UINT
GetMenuState(HMENU hMenu
, UINT id
, UINT flags
)
103 info
.cbSize
= sizeof(info
);
104 info
.fMask
= MIIM_STATE
;
105 if ( !GetMenuItemInfo(hMenu
, id
, flags
& MF_BYCOMMAND
? FALSE
: TRUE
, & info
) )
106 wxLogLastError(wxT("GetMenuItemInfo"));
111 // ============================================================================
113 // ============================================================================
115 #include <wx/listimpl.cpp>
117 WX_DEFINE_LIST( wxMenuInfoList
) ;
119 #if wxUSE_EXTENDED_RTTI
121 WX_DEFINE_FLAGS( wxMenuStyle
)
123 wxBEGIN_FLAGS( wxMenuStyle
)
124 wxFLAGS_MEMBER(wxMENU_TEAROFF
)
125 wxEND_FLAGS( wxMenuStyle
)
127 IMPLEMENT_DYNAMIC_CLASS_XTI(wxMenu
, wxEvtHandler
,"wx/menu.h")
129 wxCOLLECTION_TYPE_INFO( wxMenuItem
* , wxMenuItemList
) ;
131 template<> void wxCollectionToVariantArray( wxMenuItemList
const &theList
, wxxVariantArray
&value
)
133 wxListCollectionToVariantArray
<wxMenuItemList::compatibility_iterator
>( theList
, value
) ;
136 wxBEGIN_PROPERTIES_TABLE(wxMenu
)
137 wxEVENT_PROPERTY( Select
, wxEVT_COMMAND_MENU_SELECTED
, wxCommandEvent
)
138 wxPROPERTY( Title
, wxString
, SetTitle
, GetTitle
, wxString(), 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
139 wxREADONLY_PROPERTY_FLAGS( MenuStyle
, wxMenuStyle
, long , GetStyle
, , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
140 wxPROPERTY_COLLECTION( MenuItems
, wxMenuItemList
, wxMenuItem
* , Append
, GetMenuItems
, 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
141 wxEND_PROPERTIES_TABLE()
143 wxBEGIN_HANDLERS_TABLE(wxMenu
)
144 wxEND_HANDLERS_TABLE()
146 wxDIRECT_CONSTRUCTOR_2( wxMenu
, wxString
, Title
, long , MenuStyle
)
148 WX_DEFINE_FLAGS( wxMenuBarStyle
)
150 wxBEGIN_FLAGS( wxMenuBarStyle
)
151 wxFLAGS_MEMBER(wxMB_DOCKABLE
)
152 wxEND_FLAGS( wxMenuBarStyle
)
154 // the negative id would lead the window (its superclass !) to vetoe streaming out otherwise
155 bool wxMenuBarStreamingCallback( const wxObject
*WXUNUSED(object
), wxWriter
* , wxPersister
* , wxxVariantArray
& )
160 IMPLEMENT_DYNAMIC_CLASS_XTI_CALLBACK(wxMenuBar
, wxWindow
,"wx/menu.h",wxMenuBarStreamingCallback
)
162 IMPLEMENT_DYNAMIC_CLASS_XTI(wxMenuInfo
, wxObject
, "wx/menu.h" )
164 wxBEGIN_PROPERTIES_TABLE(wxMenuInfo
)
165 wxREADONLY_PROPERTY( Menu
, wxMenu
* , GetMenu
, , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
166 wxREADONLY_PROPERTY( Title
, wxString
, GetTitle
, wxString() , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
167 wxEND_PROPERTIES_TABLE()
169 wxBEGIN_HANDLERS_TABLE(wxMenuInfo
)
170 wxEND_HANDLERS_TABLE()
172 wxCONSTRUCTOR_2( wxMenuInfo
, wxMenu
* , Menu
, wxString
, Title
)
174 wxCOLLECTION_TYPE_INFO( wxMenuInfo
* , wxMenuInfoList
) ;
176 template<> void wxCollectionToVariantArray( wxMenuInfoList
const &theList
, wxxVariantArray
&value
)
178 wxListCollectionToVariantArray
<wxMenuInfoList::compatibility_iterator
>( theList
, value
) ;
181 wxBEGIN_PROPERTIES_TABLE(wxMenuBar
)
182 wxPROPERTY_COLLECTION( MenuInfos
, wxMenuInfoList
, wxMenuInfo
* , Append
, GetMenuInfos
, 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
183 wxEND_PROPERTIES_TABLE()
185 wxBEGIN_HANDLERS_TABLE(wxMenuBar
)
186 wxEND_HANDLERS_TABLE()
188 wxCONSTRUCTOR_DUMMY( wxMenuBar
)
191 IMPLEMENT_DYNAMIC_CLASS(wxMenu
, wxEvtHandler
)
192 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar
, wxWindow
)
193 IMPLEMENT_DYNAMIC_CLASS(wxMenuInfo
, wxObject
)
196 const wxMenuInfoList
& wxMenuBar::GetMenuInfos() const
198 wxMenuInfoList
* list
= const_cast< wxMenuInfoList
* >( &m_menuInfos
) ;
199 WX_CLEAR_LIST( wxMenuInfoList
, *list
) ;
200 for( size_t i
= 0 ; i
< GetMenuCount() ; ++i
)
202 wxMenuInfo
* info
= new wxMenuInfo() ;
203 info
->Create( const_cast<wxMenuBar
*>(this)->GetMenu(i
) , GetLabelTop(i
) ) ;
204 list
->Append( info
) ;
209 // ---------------------------------------------------------------------------
210 // wxMenu construction, adding and removing menu items
211 // ---------------------------------------------------------------------------
213 // Construct a menu with optional title (then use append)
217 m_startRadioGroup
= -1;
220 m_hMenu
= (WXHMENU
)CreatePopupMenu();
223 wxLogLastError(wxT("CreatePopupMenu"));
226 // if we have a title, insert it in the beginning of the menu
229 Append(idMenuTitle
, m_title
);
234 // The wxWindow destructor will take care of deleting the submenus.
237 // we should free Windows resources only if Windows doesn't do it for us
238 // which happens if we're attached to a menubar or a submenu of another
240 if ( !IsAttached() && !GetParent() )
242 if ( !::DestroyMenu(GetHmenu()) )
244 wxLogLastError(wxT("DestroyMenu"));
250 WX_CLEAR_ARRAY(m_accels
);
251 #endif // wxUSE_ACCEL
256 // this will take effect during the next call to Append()
260 void wxMenu::Attach(wxMenuBarBase
*menubar
)
262 wxMenuBase::Attach(menubar
);
269 int wxMenu::FindAccel(int id
) const
271 size_t n
, count
= m_accels
.GetCount();
272 for ( n
= 0; n
< count
; n
++ )
274 if ( m_accels
[n
]->m_command
== id
)
281 void wxMenu::UpdateAccel(wxMenuItem
*item
)
283 if ( item
->IsSubMenu() )
285 wxMenu
*submenu
= item
->GetSubMenu();
286 wxMenuItemList::compatibility_iterator node
= submenu
->GetMenuItems().GetFirst();
289 UpdateAccel(node
->GetData());
291 node
= node
->GetNext();
294 else if ( !item
->IsSeparator() )
296 // find the (new) accel for this item
297 wxAcceleratorEntry
*accel
= wxGetAccelFromString(item
->GetText());
299 accel
->m_command
= item
->GetId();
302 int n
= FindAccel(item
->GetId());
303 if ( n
== wxNOT_FOUND
)
305 // no old, add new if any
309 return; // skipping RebuildAccelTable() below
313 // replace old with new or just remove the old one if no new
318 m_accels
.RemoveAt(n
);
323 m_menuBar
->RebuildAccelTable();
326 //else: it is a separator, they can't have accels, nothing to do
329 #endif // wxUSE_ACCEL
331 // append a new item or submenu to the menu
332 bool wxMenu::DoInsertOrAppend(wxMenuItem
*pItem
, size_t pos
)
336 #endif // wxUSE_ACCEL
340 // if "Break" has just been called, insert a menu break before this item
341 // (and don't forget to reset the flag)
343 flags
|= MF_MENUBREAK
;
347 if ( pItem
->IsSeparator() ) {
348 flags
|= MF_SEPARATOR
;
351 // id is the numeric id for normal menu items and HMENU for submenus as
352 // required by ::AppendMenu() API
354 wxMenu
*submenu
= pItem
->GetSubMenu();
355 if ( submenu
!= NULL
) {
356 wxASSERT_MSG( submenu
->GetHMenu(), wxT("invalid submenu") );
358 submenu
->SetParent(this);
360 id
= (UINT
)submenu
->GetHMenu();
369 wxString strippedString
;
374 #if wxUSE_OWNER_DRAWN
375 if ( pItem
->IsOwnerDrawn() ) { // want to get {Measure|Draw}Item messages?
376 // item draws itself, pass pointer to it in data parameter
377 flags
|= MF_OWNERDRAW
;
378 pData
= (LPCTSTR
)pItem
;
383 // menu is just a normal string (passed in data parameter)
387 strippedString
= wxStripMenuCodes(pItem
->GetText());
388 pData
= (wxChar
*)strippedString
.c_str();
390 pData
= (wxChar
*)pItem
->GetText().c_str();
395 if ( pos
== (size_t)-1 )
397 ok
= ::AppendMenu(GetHmenu(), flags
, id
, pData
);
401 ok
= ::InsertMenu(GetHmenu(), pos
, flags
| MF_BYPOSITION
, id
, pData
);
406 wxLogLastError(wxT("Insert or AppendMenu"));
411 // if we just appended the title, highlight it
413 if ( (int)id
== idMenuTitle
)
415 // visually select the menu title
416 SetDefaultMenuItem(GetHmenu(), id
);
420 // if we're already attached to the menubar, we must update it
421 if ( IsAttached() && m_menuBar
->IsAttached() )
423 m_menuBar
->Refresh();
429 void wxMenu::EndRadioGroup()
431 // we're not inside a radio group any longer
432 m_startRadioGroup
= -1;
435 bool wxMenu::DoAppend(wxMenuItem
*item
)
437 wxCHECK_MSG( item
, FALSE
, _T("NULL item in wxMenu::DoAppend") );
441 if ( item
->GetKind() == wxITEM_RADIO
)
443 int count
= GetMenuItemCount();
445 if ( m_startRadioGroup
== -1 )
447 // start a new radio group
448 m_startRadioGroup
= count
;
450 // for now it has just one element
451 item
->SetAsRadioGroupStart();
452 item
->SetRadioGroupEnd(m_startRadioGroup
);
454 // ensure that we have a checked item in the radio group
457 else // extend the current radio group
459 // we need to update its end item
460 item
->SetRadioGroupStart(m_startRadioGroup
);
461 wxMenuItemList::compatibility_iterator node
= GetMenuItems().Item(m_startRadioGroup
);
465 node
->GetData()->SetRadioGroupEnd(count
);
469 wxFAIL_MSG( _T("where is the radio group start item?") );
473 else // not a radio item
478 if ( !wxMenuBase::DoAppend(item
) || !DoInsertOrAppend(item
) )
485 // check the item initially
492 bool wxMenu::DoInsert(size_t pos
, wxMenuItem
*item
)
494 return wxMenuBase::DoInsert(pos
, item
) && DoInsertOrAppend(item
, pos
);
497 wxMenuItem
*wxMenu::DoRemove(wxMenuItem
*item
)
499 // we need to find the items position in the child list
501 wxMenuItemList::compatibility_iterator node
= GetMenuItems().GetFirst();
502 for ( pos
= 0; node
; pos
++ )
504 if ( node
->GetData() == item
)
507 node
= node
->GetNext();
510 // DoRemove() (unlike Remove) can only be called for existing item!
511 wxCHECK_MSG( node
, NULL
, wxT("bug in wxMenu::Remove logic") );
514 // remove the corresponding accel from the accel table
515 int n
= FindAccel(item
->GetId());
516 if ( n
!= wxNOT_FOUND
)
520 m_accels
.RemoveAt(n
);
522 //else: this item doesn't have an accel, nothing to do
523 #endif // wxUSE_ACCEL
525 // remove the item from the menu
526 if ( !::RemoveMenu(GetHmenu(), (UINT
)pos
, MF_BYPOSITION
) )
528 wxLogLastError(wxT("RemoveMenu"));
531 if ( IsAttached() && m_menuBar
->IsAttached() )
533 // otherwise, the chane won't be visible
534 m_menuBar
->Refresh();
537 // and from internal data structures
538 return wxMenuBase::DoRemove(item
);
541 // ---------------------------------------------------------------------------
542 // accelerator helpers
543 // ---------------------------------------------------------------------------
547 // create the wxAcceleratorEntries for our accels and put them into provided
548 // array - return the number of accels we have
549 size_t wxMenu::CopyAccels(wxAcceleratorEntry
*accels
) const
551 size_t count
= GetAccelCount();
552 for ( size_t n
= 0; n
< count
; n
++ )
554 *accels
++ = *m_accels
[n
];
560 #endif // wxUSE_ACCEL
562 // ---------------------------------------------------------------------------
564 // ---------------------------------------------------------------------------
566 void wxMenu::SetTitle(const wxString
& label
)
568 bool hasNoTitle
= m_title
.IsEmpty();
571 HMENU hMenu
= GetHmenu();
575 if ( !label
.IsEmpty() )
577 if ( !::InsertMenu(hMenu
, 0u, MF_BYPOSITION
| MF_STRING
,
578 (unsigned)idMenuTitle
, m_title
) ||
579 !::InsertMenu(hMenu
, 1u, MF_BYPOSITION
, (unsigned)-1, NULL
) )
581 wxLogLastError(wxT("InsertMenu"));
587 if ( label
.IsEmpty() )
589 // remove the title and the separator after it
590 if ( !RemoveMenu(hMenu
, 0, MF_BYPOSITION
) ||
591 !RemoveMenu(hMenu
, 0, MF_BYPOSITION
) )
593 wxLogLastError(wxT("RemoveMenu"));
602 info
.cbSize
= sizeof(info
);
603 info
.fMask
= MIIM_TYPE
;
604 info
.fType
= MFT_STRING
;
605 info
.cch
= m_title
.Length();
606 info
.dwTypeData
= (LPTSTR
) m_title
.c_str();
607 if ( !SetMenuItemInfo(hMenu
, 0, TRUE
, & info
) )
609 wxLogLastError(wxT("SetMenuItemInfo"));
612 if ( !ModifyMenu(hMenu
, 0u,
613 MF_BYPOSITION
| MF_STRING
,
614 (unsigned)idMenuTitle
, m_title
) )
616 wxLogLastError(wxT("ModifyMenu"));
623 // put the title string in bold face
624 if ( !m_title
.IsEmpty() )
626 SetDefaultMenuItem(GetHmenu(), (UINT
)idMenuTitle
);
631 // ---------------------------------------------------------------------------
633 // ---------------------------------------------------------------------------
635 bool wxMenu::MSWCommand(WXUINT
WXUNUSED(param
), WXWORD id
)
637 // ignore commands from the menu title
639 // NB: VC++ generates wrong assembler for `if ( id != idMenuTitle )'!!
640 if ( id
!= (WXWORD
)idMenuTitle
)
642 // VZ: previosuly, the command int was set to id too which was quite
643 // useless anyhow (as it could be retrieved using GetId()) and
644 // uncompatible with wxGTK, so now we use the command int instead
645 // to pass the checked status
646 UINT menuState
= ::GetMenuState(GetHmenu(), id
, MF_BYCOMMAND
) ;
647 SendEvent(id
, menuState
& MF_CHECKED
);
653 // ---------------------------------------------------------------------------
655 // ---------------------------------------------------------------------------
657 wxWindow
*wxMenu::GetWindow() const
659 if ( m_invokingWindow
!= NULL
)
660 return m_invokingWindow
;
661 else if ( m_menuBar
!= NULL
)
662 return m_menuBar
->GetFrame();
667 // ---------------------------------------------------------------------------
669 // ---------------------------------------------------------------------------
671 void wxMenuBar::Init()
673 m_eventHandler
= this;
680 wxMenuBar::wxMenuBar()
685 wxMenuBar::wxMenuBar( long WXUNUSED(style
) )
690 wxMenuBar::wxMenuBar(int count
, wxMenu
*menus
[], const wxString titles
[])
694 m_titles
.Alloc(count
);
696 for ( int i
= 0; i
< count
; i
++ )
698 m_menus
.Append(menus
[i
]);
699 m_titles
.Add(titles
[i
]);
701 menus
[i
]->Attach(this);
705 wxMenuBar::~wxMenuBar()
707 // In Windows CE, the menubar is always associated
708 // with a toolbar, which destroys the menu implicitly.
711 GetToolBar()->SetMenuBar(NULL
);
713 // we should free Windows resources only if Windows doesn't do it for us
714 // which happens if we're attached to a frame
715 if (m_hMenu
&& !IsAttached())
717 ::DestroyMenu((HMENU
)m_hMenu
);
718 m_hMenu
= (WXHMENU
)NULL
;
723 // ---------------------------------------------------------------------------
725 // ---------------------------------------------------------------------------
727 void wxMenuBar::Refresh()
729 wxCHECK_RET( IsAttached(), wxT("can't refresh unattached menubar") );
734 CommandBar_DrawMenuBar((HWND
) GetToolBar()->GetHWND(), 0);
737 DrawMenuBar(GetHwndOf(GetFrame()));
741 WXHMENU
wxMenuBar::Create()
743 // Note: this totally doesn't work on Smartphone,
744 // since you have to use resources.
745 // We'll have to find another way to add a menu
746 // by changing/adding menu items to an existing menu.
754 HWND hCommandBar
= (HWND
) GetToolBar()->GetHWND();
755 HMENU hMenu
= (HMENU
)::SendMessage(hCommandBar
, SHCMBM_GETMENU
, (WPARAM
)0, (LPARAM
)0);
759 memset(&tbButton
, 0, sizeof(TBBUTTON
));
760 tbButton
.iBitmap
= I_IMAGENONE
;
761 tbButton
.fsState
= TBSTATE_ENABLED
;
762 tbButton
.fsStyle
= TBSTYLE_DROPDOWN
| TBSTYLE_NO_DROPDOWN_ARROW
| TBSTYLE_AUTOSIZE
;
765 for (i
= 0; i
< GetMenuCount(); i
++)
767 HMENU hPopupMenu
= (HMENU
) GetMenu(i
)->GetHMenu() ;
768 tbButton
.dwData
= (DWORD
)hPopupMenu
;
769 wxString label
= wxStripMenuCodes(GetLabelTop(i
));
770 tbButton
.iString
= (int) label
.c_str();
774 tbButton
.idCommand
= NewControlId();
775 if (!::SendMessage(hCommandBar
, TB_INSERTBUTTON
, position
, (LPARAM
)&tbButton
))
777 wxLogLastError(wxT("TB_INSERTBUTTON"));
781 m_hMenu
= (WXHMENU
) hMenu
;
787 m_hMenu
= (WXHMENU
)::CreateMenu();
791 wxLogLastError(wxT("CreateMenu"));
795 size_t count
= GetMenuCount(), i
;
796 wxMenuList::iterator it
;
797 for ( i
= 0, it
= m_menus
.begin(); i
< count
; i
++, it
++ )
799 if ( !::AppendMenu((HMENU
)m_hMenu
, MF_POPUP
| MF_STRING
,
800 (UINT
)(*it
)->GetHMenu(),
803 wxLogLastError(wxT("AppendMenu"));
812 // ---------------------------------------------------------------------------
813 // wxMenuBar functions to work with the top level submenus
814 // ---------------------------------------------------------------------------
816 // NB: we don't support owner drawn top level items for now, if we do these
817 // functions would have to be changed to use wxMenuItem as well
819 void wxMenuBar::EnableTop(size_t pos
, bool enable
)
821 wxCHECK_RET( IsAttached(), wxT("doesn't work with unattached menubars") );
823 int flag
= enable
? MF_ENABLED
: MF_GRAYED
;
825 EnableMenuItem((HMENU
)m_hMenu
, pos
, MF_BYPOSITION
| flag
);
830 void wxMenuBar::SetLabelTop(size_t pos
, const wxString
& label
)
832 wxCHECK_RET( pos
< GetMenuCount(), wxT("invalid menu index") );
834 m_titles
[pos
] = label
;
840 //else: have to modify the existing menu
843 UINT flagsOld
= ::GetMenuState((HMENU
)m_hMenu
, pos
, MF_BYPOSITION
);
844 if ( flagsOld
== 0xFFFFFFFF )
846 wxLogLastError(wxT("GetMenuState"));
851 if ( flagsOld
& MF_POPUP
)
853 // HIBYTE contains the number of items in the submenu in this case
855 id
= (UINT
)::GetSubMenu((HMENU
)m_hMenu
, pos
);
865 info
.cbSize
= sizeof(info
);
866 info
.fMask
= MIIM_TYPE
;
867 info
.fType
= MFT_STRING
;
868 info
.cch
= label
.Length();
869 info
.dwTypeData
= (LPTSTR
) label
.c_str();
870 if ( !SetMenuItemInfo(GetHmenu(), id
, TRUE
, & info
) )
872 wxLogLastError(wxT("SetMenuItemInfo"));
876 if ( ::ModifyMenu(GetHmenu(), pos
, MF_BYPOSITION
| MF_STRING
| flagsOld
,
877 id
, label
) == (int)0xFFFFFFFF )
879 wxLogLastError(wxT("ModifyMenu"));
886 wxString
wxMenuBar::GetLabelTop(size_t pos
) const
888 wxCHECK_MSG( pos
< GetMenuCount(), wxEmptyString
,
889 wxT("invalid menu index in wxMenuBar::GetLabelTop") );
891 return m_titles
[pos
];
894 // ---------------------------------------------------------------------------
895 // wxMenuBar construction
896 // ---------------------------------------------------------------------------
898 wxMenu
*wxMenuBar::Replace(size_t pos
, wxMenu
*menu
, const wxString
& title
)
900 wxMenu
*menuOld
= wxMenuBarBase::Replace(pos
, menu
, title
);
904 m_titles
[pos
] = title
;
908 // can't use ModifyMenu() because it deletes the submenu it replaces
909 if ( !::RemoveMenu(GetHmenu(), (UINT
)pos
, MF_BYPOSITION
) )
911 wxLogLastError(wxT("RemoveMenu"));
914 if ( !::InsertMenu(GetHmenu(), (UINT
)pos
,
915 MF_BYPOSITION
| MF_POPUP
| MF_STRING
,
916 (UINT
)GetHmenuOf(menu
), title
) )
918 wxLogLastError(wxT("InsertMenu"));
922 if ( menuOld
->HasAccels() || menu
->HasAccels() )
924 // need to rebuild accell table
927 #endif // wxUSE_ACCEL
935 bool wxMenuBar::Insert(size_t pos
, wxMenu
*menu
, const wxString
& title
)
937 if ( !wxMenuBarBase::Insert(pos
, menu
, title
) )
940 m_titles
.Insert(title
, pos
);
948 memset(&tbButton
, 0, sizeof(TBBUTTON
));
949 tbButton
.iBitmap
= I_IMAGENONE
;
950 tbButton
.fsState
= TBSTATE_ENABLED
;
951 tbButton
.fsStyle
= TBSTYLE_DROPDOWN
| TBSTYLE_NO_DROPDOWN_ARROW
| TBSTYLE_AUTOSIZE
;
953 HMENU hPopupMenu
= (HMENU
) menu
->GetHMenu() ;
954 tbButton
.dwData
= (DWORD
)hPopupMenu
;
955 wxString label
= wxStripMenuCodes(title
);
956 tbButton
.iString
= (int) label
.c_str();
958 tbButton
.idCommand
= NewControlId();
959 if (!::SendMessage((HWND
) GetToolBar()->GetHWND(), TB_INSERTBUTTON
, pos
, (LPARAM
)&tbButton
))
961 wxLogLastError(wxT("TB_INSERTBUTTON"));
965 if ( !::InsertMenu(GetHmenu(), pos
,
966 MF_BYPOSITION
| MF_POPUP
| MF_STRING
,
967 (UINT
)GetHmenuOf(menu
), title
) )
969 wxLogLastError(wxT("InsertMenu"));
973 if ( menu
->HasAccels() )
975 // need to rebuild accell table
978 #endif // wxUSE_ACCEL
986 bool wxMenuBar::Append(wxMenu
*menu
, const wxString
& title
)
988 WXHMENU submenu
= menu
? menu
->GetHMenu() : 0;
989 wxCHECK_MSG( submenu
, FALSE
, wxT("can't append invalid menu to menubar") );
991 if ( !wxMenuBarBase::Append(menu
, title
) )
1002 memset(&tbButton
, 0, sizeof(TBBUTTON
));
1003 tbButton
.iBitmap
= I_IMAGENONE
;
1004 tbButton
.fsState
= TBSTATE_ENABLED
;
1005 tbButton
.fsStyle
= TBSTYLE_DROPDOWN
| TBSTYLE_NO_DROPDOWN_ARROW
| TBSTYLE_AUTOSIZE
;
1007 size_t pos
= GetMenuCount();
1008 HMENU hPopupMenu
= (HMENU
) menu
->GetHMenu() ;
1009 tbButton
.dwData
= (DWORD
)hPopupMenu
;
1010 wxString label
= wxStripMenuCodes(title
);
1011 tbButton
.iString
= (int) label
.c_str();
1013 tbButton
.idCommand
= NewControlId();
1014 if (!::SendMessage((HWND
) GetToolBar()->GetHWND(), TB_INSERTBUTTON
, pos
, (LPARAM
)&tbButton
))
1016 wxLogLastError(wxT("TB_INSERTBUTTON"));
1020 if ( !::AppendMenu(GetHmenu(), MF_POPUP
| MF_STRING
,
1021 (UINT
)submenu
, title
) )
1023 wxLogLastError(wxT("AppendMenu"));
1028 if ( menu
->HasAccels() )
1030 // need to rebuild accelerator table
1031 RebuildAccelTable();
1033 #endif // wxUSE_ACCEL
1041 wxMenu
*wxMenuBar::Remove(size_t pos
)
1043 wxMenu
*menu
= wxMenuBarBase::Remove(pos
);
1052 if (!::SendMessage((HWND
) GetToolBar()->GetHWND(), TB_DELETEBUTTON
, (UINT
) pos
, (LPARAM
) 0))
1054 wxLogLastError(wxT("TB_DELETEBUTTON"));
1058 if ( !::RemoveMenu(GetHmenu(), (UINT
)pos
, MF_BYPOSITION
) )
1060 wxLogLastError(wxT("RemoveMenu"));
1064 if ( menu
->HasAccels() )
1066 // need to rebuild accell table
1067 RebuildAccelTable();
1069 #endif // wxUSE_ACCEL
1074 m_titles
.RemoveAt(pos
);
1081 void wxMenuBar::RebuildAccelTable()
1083 // merge the accelerators of all menus into one accel table
1084 size_t nAccelCount
= 0;
1085 size_t i
, count
= GetMenuCount();
1086 wxMenuList::iterator it
;
1087 for ( i
= 0, it
= m_menus
.begin(); i
< count
; i
++, it
++ )
1089 nAccelCount
+= (*it
)->GetAccelCount();
1094 wxAcceleratorEntry
*accelEntries
= new wxAcceleratorEntry
[nAccelCount
];
1097 for ( i
= 0, it
= m_menus
.begin(); i
< count
; i
++, it
++ )
1099 nAccelCount
+= (*it
)->CopyAccels(&accelEntries
[nAccelCount
]);
1102 m_accelTable
= wxAcceleratorTable(nAccelCount
, accelEntries
);
1104 delete [] accelEntries
;
1108 #endif // wxUSE_ACCEL
1110 void wxMenuBar::Attach(wxFrame
*frame
)
1112 wxMenuBarBase::Attach(frame
);
1115 RebuildAccelTable();
1116 #endif // wxUSE_ACCEL
1119 void wxMenuBar::Detach()
1121 wxMenuBarBase::Detach();
1124 #endif // wxUSE_MENUS