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"
43 #include "wx/ownerdrw.h"
46 #include "wx/msw/private.h"
57 #ifndef TBSTYLE_NO_DROPDOWN_ARROW
58 #define TBSTYLE_NO_DROPDOWN_ARROW 0x0080
63 // other standard headers
66 // ----------------------------------------------------------------------------
68 // ----------------------------------------------------------------------------
70 extern wxMenu
*wxCurrentPopupMenu
;
72 // ----------------------------------------------------------------------------
74 // ----------------------------------------------------------------------------
76 // the (popup) menu title has this special id
77 static const int idMenuTitle
= -2;
79 // ----------------------------------------------------------------------------
81 // ----------------------------------------------------------------------------
83 // make the given menu item default
84 static void SetDefaultMenuItem(HMENU hmenu
, UINT id
)
89 mii
.cbSize
= sizeof(MENUITEMINFO
);
90 mii
.fMask
= MIIM_STATE
;
91 mii
.fState
= MFS_DEFAULT
;
93 if ( !::SetMenuItemInfo(hmenu
, id
, FALSE
, &mii
) )
95 wxLogLastError(wxT("SetMenuItemInfo"));
101 UINT
GetMenuState(HMENU hMenu
, UINT id
, UINT flags
)
105 info
.cbSize
= sizeof(info
);
106 info
.fMask
= MIIM_STATE
;
107 if ( !GetMenuItemInfo(hMenu
, id
, flags
& MF_BYCOMMAND
? FALSE
: TRUE
, & info
) )
108 wxLogLastError(wxT("GetMenuItemInfo"));
113 // ============================================================================
115 // ============================================================================
117 #include <wx/listimpl.cpp>
119 WX_DEFINE_LIST( wxMenuInfoList
) ;
121 #if wxUSE_EXTENDED_RTTI
123 WX_DEFINE_FLAGS( wxMenuStyle
)
125 wxBEGIN_FLAGS( wxMenuStyle
)
126 wxFLAGS_MEMBER(wxMENU_TEAROFF
)
127 wxEND_FLAGS( wxMenuStyle
)
129 IMPLEMENT_DYNAMIC_CLASS_XTI(wxMenu
, wxEvtHandler
,"wx/menu.h")
131 wxCOLLECTION_TYPE_INFO( wxMenuItem
* , wxMenuItemList
) ;
133 template<> void wxCollectionToVariantArray( wxMenuItemList
const &theList
, wxxVariantArray
&value
)
135 wxListCollectionToVariantArray
<wxMenuItemList::compatibility_iterator
>( theList
, value
) ;
138 wxBEGIN_PROPERTIES_TABLE(wxMenu
)
139 wxEVENT_PROPERTY( Select
, wxEVT_COMMAND_MENU_SELECTED
, wxCommandEvent
)
140 wxPROPERTY( Title
, wxString
, SetTitle
, GetTitle
, wxString(), 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
141 wxREADONLY_PROPERTY_FLAGS( MenuStyle
, wxMenuStyle
, long , GetStyle
, , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
142 wxPROPERTY_COLLECTION( MenuItems
, wxMenuItemList
, wxMenuItem
* , Append
, GetMenuItems
, 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
143 wxEND_PROPERTIES_TABLE()
145 wxBEGIN_HANDLERS_TABLE(wxMenu
)
146 wxEND_HANDLERS_TABLE()
148 wxDIRECT_CONSTRUCTOR_2( wxMenu
, wxString
, Title
, long , MenuStyle
)
150 WX_DEFINE_FLAGS( wxMenuBarStyle
)
152 wxBEGIN_FLAGS( wxMenuBarStyle
)
153 wxFLAGS_MEMBER(wxMB_DOCKABLE
)
154 wxEND_FLAGS( wxMenuBarStyle
)
156 // the negative id would lead the window (its superclass !) to vetoe streaming out otherwise
157 bool wxMenuBarStreamingCallback( const wxObject
*WXUNUSED(object
), wxWriter
* , wxPersister
* , wxxVariantArray
& )
162 IMPLEMENT_DYNAMIC_CLASS_XTI_CALLBACK(wxMenuBar
, wxWindow
,"wx/menu.h",wxMenuBarStreamingCallback
)
164 IMPLEMENT_DYNAMIC_CLASS_XTI(wxMenuInfo
, wxObject
, "wx/menu.h" )
166 wxBEGIN_PROPERTIES_TABLE(wxMenuInfo
)
167 wxREADONLY_PROPERTY( Menu
, wxMenu
* , GetMenu
, , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
168 wxREADONLY_PROPERTY( Title
, wxString
, GetTitle
, wxString() , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
169 wxEND_PROPERTIES_TABLE()
171 wxBEGIN_HANDLERS_TABLE(wxMenuInfo
)
172 wxEND_HANDLERS_TABLE()
174 wxCONSTRUCTOR_2( wxMenuInfo
, wxMenu
* , Menu
, wxString
, Title
)
176 wxCOLLECTION_TYPE_INFO( wxMenuInfo
* , wxMenuInfoList
) ;
178 template<> void wxCollectionToVariantArray( wxMenuInfoList
const &theList
, wxxVariantArray
&value
)
180 wxListCollectionToVariantArray
<wxMenuInfoList::compatibility_iterator
>( theList
, value
) ;
183 wxBEGIN_PROPERTIES_TABLE(wxMenuBar
)
184 wxPROPERTY_COLLECTION( MenuInfos
, wxMenuInfoList
, wxMenuInfo
* , Append
, GetMenuInfos
, 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
185 wxEND_PROPERTIES_TABLE()
187 wxBEGIN_HANDLERS_TABLE(wxMenuBar
)
188 wxEND_HANDLERS_TABLE()
190 wxCONSTRUCTOR_DUMMY( wxMenuBar
)
193 IMPLEMENT_DYNAMIC_CLASS(wxMenu
, wxEvtHandler
)
194 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar
, wxWindow
)
195 IMPLEMENT_DYNAMIC_CLASS(wxMenuInfo
, wxObject
)
198 const wxMenuInfoList
& wxMenuBar::GetMenuInfos() const
200 wxMenuInfoList
* list
= const_cast< wxMenuInfoList
* >( &m_menuInfos
) ;
201 WX_CLEAR_LIST( wxMenuInfoList
, *list
) ;
202 for( size_t i
= 0 ; i
< GetMenuCount() ; ++i
)
204 wxMenuInfo
* info
= new wxMenuInfo() ;
205 info
->Create( const_cast<wxMenuBar
*>(this)->GetMenu(i
) , GetLabelTop(i
) ) ;
206 list
->Append( info
) ;
211 // ---------------------------------------------------------------------------
212 // wxMenu construction, adding and removing menu items
213 // ---------------------------------------------------------------------------
215 // Construct a menu with optional title (then use append)
219 m_startRadioGroup
= -1;
222 m_hMenu
= (WXHMENU
)CreatePopupMenu();
225 wxLogLastError(wxT("CreatePopupMenu"));
228 // if we have a title, insert it in the beginning of the menu
231 Append(idMenuTitle
, m_title
);
236 // The wxWindow destructor will take care of deleting the submenus.
239 // we should free Windows resources only if Windows doesn't do it for us
240 // which happens if we're attached to a menubar or a submenu of another
242 if ( !IsAttached() && !GetParent() )
244 if ( !::DestroyMenu(GetHmenu()) )
246 wxLogLastError(wxT("DestroyMenu"));
252 WX_CLEAR_ARRAY(m_accels
);
253 #endif // wxUSE_ACCEL
258 // this will take effect during the next call to Append()
262 void wxMenu::Attach(wxMenuBarBase
*menubar
)
264 wxMenuBase::Attach(menubar
);
271 int wxMenu::FindAccel(int id
) const
273 size_t n
, count
= m_accels
.GetCount();
274 for ( n
= 0; n
< count
; n
++ )
276 if ( m_accels
[n
]->m_command
== id
)
283 void wxMenu::UpdateAccel(wxMenuItem
*item
)
285 if ( item
->IsSubMenu() )
287 wxMenu
*submenu
= item
->GetSubMenu();
288 wxMenuItemList::compatibility_iterator node
= submenu
->GetMenuItems().GetFirst();
291 UpdateAccel(node
->GetData());
293 node
= node
->GetNext();
296 else if ( !item
->IsSeparator() )
298 // find the (new) accel for this item
299 wxAcceleratorEntry
*accel
= wxGetAccelFromString(item
->GetText());
301 accel
->m_command
= item
->GetId();
304 int n
= FindAccel(item
->GetId());
305 if ( n
== wxNOT_FOUND
)
307 // no old, add new if any
311 return; // skipping RebuildAccelTable() below
315 // replace old with new or just remove the old one if no new
320 m_accels
.RemoveAt(n
);
325 m_menuBar
->RebuildAccelTable();
328 //else: it is a separator, they can't have accels, nothing to do
331 #endif // wxUSE_ACCEL
333 // append a new item or submenu to the menu
334 bool wxMenu::DoInsertOrAppend(wxMenuItem
*pItem
, size_t pos
)
338 #endif // wxUSE_ACCEL
342 // if "Break" has just been called, insert a menu break before this item
343 // (and don't forget to reset the flag)
345 flags
|= MF_MENUBREAK
;
349 if ( pItem
->IsSeparator() ) {
350 flags
|= MF_SEPARATOR
;
353 // id is the numeric id for normal menu items and HMENU for submenus as
354 // required by ::AppendMenu() API
356 wxMenu
*submenu
= pItem
->GetSubMenu();
357 if ( submenu
!= NULL
) {
358 wxASSERT_MSG( submenu
->GetHMenu(), wxT("invalid submenu") );
360 submenu
->SetParent(this);
362 id
= (UINT
)submenu
->GetHMenu();
371 wxString strippedString
;
376 #if wxUSE_OWNER_DRAWN
377 if ( pItem
->IsOwnerDrawn() ) { // want to get {Measure|Draw}Item messages?
378 // item draws itself, pass pointer to it in data parameter
379 flags
|= MF_OWNERDRAW
;
380 pData
= (LPCTSTR
)pItem
;
385 // menu is just a normal string (passed in data parameter)
389 strippedString
= wxStripMenuCodes(pItem
->GetText());
390 pData
= (wxChar
*)strippedString
.c_str();
392 pData
= (wxChar
*)pItem
->GetText().c_str();
397 if ( pos
== (size_t)-1 )
399 ok
= ::AppendMenu(GetHmenu(), flags
, id
, pData
);
403 ok
= ::InsertMenu(GetHmenu(), pos
, flags
| MF_BYPOSITION
, id
, pData
);
408 wxLogLastError(wxT("Insert or AppendMenu"));
413 // if we just appended the title, highlight it
415 if ( (int)id
== idMenuTitle
)
417 // visually select the menu title
418 SetDefaultMenuItem(GetHmenu(), id
);
422 // if we're already attached to the menubar, we must update it
423 if ( IsAttached() && m_menuBar
->IsAttached() )
425 m_menuBar
->Refresh();
431 void wxMenu::EndRadioGroup()
433 // we're not inside a radio group any longer
434 m_startRadioGroup
= -1;
437 bool wxMenu::DoAppend(wxMenuItem
*item
)
439 wxCHECK_MSG( item
, FALSE
, _T("NULL item in wxMenu::DoAppend") );
443 if ( item
->GetKind() == wxITEM_RADIO
)
445 int count
= GetMenuItemCount();
447 if ( m_startRadioGroup
== -1 )
449 // start a new radio group
450 m_startRadioGroup
= count
;
452 // for now it has just one element
453 item
->SetAsRadioGroupStart();
454 item
->SetRadioGroupEnd(m_startRadioGroup
);
456 // ensure that we have a checked item in the radio group
459 else // extend the current radio group
461 // we need to update its end item
462 item
->SetRadioGroupStart(m_startRadioGroup
);
463 wxMenuItemList::compatibility_iterator node
= GetMenuItems().Item(m_startRadioGroup
);
467 node
->GetData()->SetRadioGroupEnd(count
);
471 wxFAIL_MSG( _T("where is the radio group start item?") );
475 else // not a radio item
480 if ( !wxMenuBase::DoAppend(item
) || !DoInsertOrAppend(item
) )
487 // check the item initially
494 bool wxMenu::DoInsert(size_t pos
, wxMenuItem
*item
)
496 return wxMenuBase::DoInsert(pos
, item
) && DoInsertOrAppend(item
, pos
);
499 wxMenuItem
*wxMenu::DoRemove(wxMenuItem
*item
)
501 // we need to find the items position in the child list
503 wxMenuItemList::compatibility_iterator node
= GetMenuItems().GetFirst();
504 for ( pos
= 0; node
; pos
++ )
506 if ( node
->GetData() == item
)
509 node
= node
->GetNext();
512 // DoRemove() (unlike Remove) can only be called for existing item!
513 wxCHECK_MSG( node
, NULL
, wxT("bug in wxMenu::Remove logic") );
516 // remove the corresponding accel from the accel table
517 int n
= FindAccel(item
->GetId());
518 if ( n
!= wxNOT_FOUND
)
522 m_accels
.RemoveAt(n
);
524 //else: this item doesn't have an accel, nothing to do
525 #endif // wxUSE_ACCEL
527 // remove the item from the menu
528 if ( !::RemoveMenu(GetHmenu(), (UINT
)pos
, MF_BYPOSITION
) )
530 wxLogLastError(wxT("RemoveMenu"));
533 if ( IsAttached() && m_menuBar
->IsAttached() )
535 // otherwise, the chane won't be visible
536 m_menuBar
->Refresh();
539 // and from internal data structures
540 return wxMenuBase::DoRemove(item
);
543 // ---------------------------------------------------------------------------
544 // accelerator helpers
545 // ---------------------------------------------------------------------------
549 // create the wxAcceleratorEntries for our accels and put them into provided
550 // array - return the number of accels we have
551 size_t wxMenu::CopyAccels(wxAcceleratorEntry
*accels
) const
553 size_t count
= GetAccelCount();
554 for ( size_t n
= 0; n
< count
; n
++ )
556 *accels
++ = *m_accels
[n
];
562 #endif // wxUSE_ACCEL
564 // ---------------------------------------------------------------------------
566 // ---------------------------------------------------------------------------
568 void wxMenu::SetTitle(const wxString
& label
)
570 bool hasNoTitle
= m_title
.IsEmpty();
573 HMENU hMenu
= GetHmenu();
577 if ( !label
.IsEmpty() )
579 if ( !::InsertMenu(hMenu
, 0u, MF_BYPOSITION
| MF_STRING
,
580 (unsigned)idMenuTitle
, m_title
) ||
581 !::InsertMenu(hMenu
, 1u, MF_BYPOSITION
, (unsigned)-1, NULL
) )
583 wxLogLastError(wxT("InsertMenu"));
589 if ( label
.IsEmpty() )
591 // remove the title and the separator after it
592 if ( !RemoveMenu(hMenu
, 0, MF_BYPOSITION
) ||
593 !RemoveMenu(hMenu
, 0, MF_BYPOSITION
) )
595 wxLogLastError(wxT("RemoveMenu"));
604 info
.cbSize
= sizeof(info
);
605 info
.fMask
= MIIM_TYPE
;
606 info
.fType
= MFT_STRING
;
607 info
.cch
= m_title
.Length();
608 info
.dwTypeData
= (LPTSTR
) m_title
.c_str();
609 if ( !SetMenuItemInfo(hMenu
, 0, TRUE
, & info
) )
611 wxLogLastError(wxT("SetMenuItemInfo"));
614 if ( !ModifyMenu(hMenu
, 0u,
615 MF_BYPOSITION
| MF_STRING
,
616 (unsigned)idMenuTitle
, m_title
) )
618 wxLogLastError(wxT("ModifyMenu"));
625 // put the title string in bold face
626 if ( !m_title
.IsEmpty() )
628 SetDefaultMenuItem(GetHmenu(), (UINT
)idMenuTitle
);
633 // ---------------------------------------------------------------------------
635 // ---------------------------------------------------------------------------
637 bool wxMenu::MSWCommand(WXUINT
WXUNUSED(param
), WXWORD id
)
639 // ignore commands from the menu title
641 // NB: VC++ generates wrong assembler for `if ( id != idMenuTitle )'!!
642 if ( id
!= (WXWORD
)idMenuTitle
)
644 // VZ: previosuly, the command int was set to id too which was quite
645 // useless anyhow (as it could be retrieved using GetId()) and
646 // uncompatible with wxGTK, so now we use the command int instead
647 // to pass the checked status
648 UINT menuState
= ::GetMenuState(GetHmenu(), id
, MF_BYCOMMAND
) ;
649 SendEvent(id
, menuState
& MF_CHECKED
);
655 // ---------------------------------------------------------------------------
657 // ---------------------------------------------------------------------------
659 wxWindow
*wxMenu::GetWindow() const
661 if ( m_invokingWindow
!= NULL
)
662 return m_invokingWindow
;
663 else if ( m_menuBar
!= NULL
)
664 return m_menuBar
->GetFrame();
669 // ---------------------------------------------------------------------------
671 // ---------------------------------------------------------------------------
673 void wxMenuBar::Init()
675 m_eventHandler
= this;
682 wxMenuBar::wxMenuBar()
687 wxMenuBar::wxMenuBar( long WXUNUSED(style
) )
692 wxMenuBar::wxMenuBar(int count
, wxMenu
*menus
[], const wxString titles
[])
696 m_titles
.Alloc(count
);
698 for ( int i
= 0; i
< count
; i
++ )
700 m_menus
.Append(menus
[i
]);
701 m_titles
.Add(titles
[i
]);
703 menus
[i
]->Attach(this);
707 wxMenuBar::~wxMenuBar()
709 // In Windows CE, the menubar is always associated
710 // with a toolbar, which destroys the menu implicitly.
713 GetToolBar()->SetMenuBar(NULL
);
715 // we should free Windows resources only if Windows doesn't do it for us
716 // which happens if we're attached to a frame
717 if (m_hMenu
&& !IsAttached())
719 ::DestroyMenu((HMENU
)m_hMenu
);
720 m_hMenu
= (WXHMENU
)NULL
;
725 // ---------------------------------------------------------------------------
727 // ---------------------------------------------------------------------------
729 void wxMenuBar::Refresh()
731 wxCHECK_RET( IsAttached(), wxT("can't refresh unattached menubar") );
736 CommandBar_DrawMenuBar((HWND
) GetToolBar()->GetHWND(), 0);
739 DrawMenuBar(GetHwndOf(GetFrame()));
743 WXHMENU
wxMenuBar::Create()
745 // Note: this totally doesn't work on Smartphone,
746 // since you have to use resources.
747 // We'll have to find another way to add a menu
748 // by changing/adding menu items to an existing menu.
756 HWND hCommandBar
= (HWND
) GetToolBar()->GetHWND();
757 HMENU hMenu
= (HMENU
)::SendMessage(hCommandBar
, SHCMBM_GETMENU
, (WPARAM
)0, (LPARAM
)0);
761 memset(&tbButton
, 0, sizeof(TBBUTTON
));
762 tbButton
.iBitmap
= I_IMAGENONE
;
763 tbButton
.fsState
= TBSTATE_ENABLED
;
764 tbButton
.fsStyle
= TBSTYLE_DROPDOWN
| TBSTYLE_NO_DROPDOWN_ARROW
| TBSTYLE_AUTOSIZE
;
767 for (i
= 0; i
< GetMenuCount(); i
++)
769 HMENU hPopupMenu
= (HMENU
) GetMenu(i
)->GetHMenu() ;
770 tbButton
.dwData
= (DWORD
)hPopupMenu
;
771 wxString label
= wxStripMenuCodes(GetLabelTop(i
));
772 tbButton
.iString
= (int) label
.c_str();
776 tbButton
.idCommand
= NewControlId();
777 if (!::SendMessage(hCommandBar
, TB_INSERTBUTTON
, position
, (LPARAM
)&tbButton
))
779 wxLogLastError(wxT("TB_INSERTBUTTON"));
783 m_hMenu
= (WXHMENU
) hMenu
;
789 m_hMenu
= (WXHMENU
)::CreateMenu();
793 wxLogLastError(wxT("CreateMenu"));
797 size_t count
= GetMenuCount(), i
;
798 wxMenuList::iterator it
;
799 for ( i
= 0, it
= m_menus
.begin(); i
< count
; i
++, it
++ )
801 if ( !::AppendMenu((HMENU
)m_hMenu
, MF_POPUP
| MF_STRING
,
802 (UINT
)(*it
)->GetHMenu(),
805 wxLogLastError(wxT("AppendMenu"));
814 // ---------------------------------------------------------------------------
815 // wxMenuBar functions to work with the top level submenus
816 // ---------------------------------------------------------------------------
818 // NB: we don't support owner drawn top level items for now, if we do these
819 // functions would have to be changed to use wxMenuItem as well
821 void wxMenuBar::EnableTop(size_t pos
, bool enable
)
823 wxCHECK_RET( IsAttached(), wxT("doesn't work with unattached menubars") );
825 int flag
= enable
? MF_ENABLED
: MF_GRAYED
;
827 EnableMenuItem((HMENU
)m_hMenu
, pos
, MF_BYPOSITION
| flag
);
832 void wxMenuBar::SetLabelTop(size_t pos
, const wxString
& label
)
834 wxCHECK_RET( pos
< GetMenuCount(), wxT("invalid menu index") );
836 m_titles
[pos
] = label
;
842 //else: have to modify the existing menu
845 UINT flagsOld
= ::GetMenuState((HMENU
)m_hMenu
, pos
, MF_BYPOSITION
);
846 if ( flagsOld
== 0xFFFFFFFF )
848 wxLogLastError(wxT("GetMenuState"));
853 if ( flagsOld
& MF_POPUP
)
855 // HIBYTE contains the number of items in the submenu in this case
857 id
= (UINT
)::GetSubMenu((HMENU
)m_hMenu
, pos
);
867 info
.cbSize
= sizeof(info
);
868 info
.fMask
= MIIM_TYPE
;
869 info
.fType
= MFT_STRING
;
870 info
.cch
= label
.Length();
871 info
.dwTypeData
= (LPTSTR
) label
.c_str();
872 if ( !SetMenuItemInfo(GetHmenu(), id
, TRUE
, & info
) )
874 wxLogLastError(wxT("SetMenuItemInfo"));
878 if ( ::ModifyMenu(GetHmenu(), pos
, MF_BYPOSITION
| MF_STRING
| flagsOld
,
879 id
, label
) == (int)0xFFFFFFFF )
881 wxLogLastError(wxT("ModifyMenu"));
888 wxString
wxMenuBar::GetLabelTop(size_t pos
) const
890 wxCHECK_MSG( pos
< GetMenuCount(), wxEmptyString
,
891 wxT("invalid menu index in wxMenuBar::GetLabelTop") );
893 return wxMenuItem::GetLabelFromText(m_titles
[pos
]);
896 // ---------------------------------------------------------------------------
897 // wxMenuBar construction
898 // ---------------------------------------------------------------------------
900 wxMenu
*wxMenuBar::Replace(size_t pos
, wxMenu
*menu
, const wxString
& title
)
902 wxMenu
*menuOld
= wxMenuBarBase::Replace(pos
, menu
, title
);
906 m_titles
[pos
] = title
;
910 // can't use ModifyMenu() because it deletes the submenu it replaces
911 if ( !::RemoveMenu(GetHmenu(), (UINT
)pos
, MF_BYPOSITION
) )
913 wxLogLastError(wxT("RemoveMenu"));
916 if ( !::InsertMenu(GetHmenu(), (UINT
)pos
,
917 MF_BYPOSITION
| MF_POPUP
| MF_STRING
,
918 (UINT
)GetHmenuOf(menu
), title
) )
920 wxLogLastError(wxT("InsertMenu"));
924 if ( menuOld
->HasAccels() || menu
->HasAccels() )
926 // need to rebuild accell table
929 #endif // wxUSE_ACCEL
937 bool wxMenuBar::Insert(size_t pos
, wxMenu
*menu
, const wxString
& title
)
939 if ( !wxMenuBarBase::Insert(pos
, menu
, title
) )
942 m_titles
.Insert(title
, pos
);
950 memset(&tbButton
, 0, sizeof(TBBUTTON
));
951 tbButton
.iBitmap
= I_IMAGENONE
;
952 tbButton
.fsState
= TBSTATE_ENABLED
;
953 tbButton
.fsStyle
= TBSTYLE_DROPDOWN
| TBSTYLE_NO_DROPDOWN_ARROW
| TBSTYLE_AUTOSIZE
;
955 HMENU hPopupMenu
= (HMENU
) menu
->GetHMenu() ;
956 tbButton
.dwData
= (DWORD
)hPopupMenu
;
957 wxString label
= wxStripMenuCodes(title
);
958 tbButton
.iString
= (int) label
.c_str();
960 tbButton
.idCommand
= NewControlId();
961 if (!::SendMessage((HWND
) GetToolBar()->GetHWND(), TB_INSERTBUTTON
, pos
, (LPARAM
)&tbButton
))
963 wxLogLastError(wxT("TB_INSERTBUTTON"));
967 if ( !::InsertMenu(GetHmenu(), pos
,
968 MF_BYPOSITION
| MF_POPUP
| MF_STRING
,
969 (UINT
)GetHmenuOf(menu
), title
) )
971 wxLogLastError(wxT("InsertMenu"));
975 if ( menu
->HasAccels() )
977 // need to rebuild accell table
980 #endif // wxUSE_ACCEL
988 bool wxMenuBar::Append(wxMenu
*menu
, const wxString
& title
)
990 WXHMENU submenu
= menu
? menu
->GetHMenu() : 0;
991 wxCHECK_MSG( submenu
, FALSE
, wxT("can't append invalid menu to menubar") );
993 if ( !wxMenuBarBase::Append(menu
, title
) )
1004 memset(&tbButton
, 0, sizeof(TBBUTTON
));
1005 tbButton
.iBitmap
= I_IMAGENONE
;
1006 tbButton
.fsState
= TBSTATE_ENABLED
;
1007 tbButton
.fsStyle
= TBSTYLE_DROPDOWN
| TBSTYLE_NO_DROPDOWN_ARROW
| TBSTYLE_AUTOSIZE
;
1009 size_t pos
= GetMenuCount();
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 ( !::AppendMenu(GetHmenu(), MF_POPUP
| MF_STRING
,
1023 (UINT
)submenu
, title
) )
1025 wxLogLastError(wxT("AppendMenu"));
1030 if ( menu
->HasAccels() )
1032 // need to rebuild accelerator table
1033 RebuildAccelTable();
1035 #endif // wxUSE_ACCEL
1043 wxMenu
*wxMenuBar::Remove(size_t pos
)
1045 wxMenu
*menu
= wxMenuBarBase::Remove(pos
);
1049 size_t arraypos
= pos
;
1057 if (!::SendMessage((HWND
) GetToolBar()->GetHWND(), TB_DELETEBUTTON
, (UINT
) pos
, (LPARAM
) 0))
1059 wxLogLastError(wxT("TB_DELETEBUTTON"));
1063 #if wxUSE_MDI_ARCHITECTURE
1064 //MDI - window menu stuff
1065 if (GetFrame() && GetFrame()->IsKindOf(CLASSINFO(wxMDIParentFrame
)))
1067 //There's two cases which we need to deal with in order
1068 //to remove at the correct index with MDI windows
1070 //#1 is due to the fact that wxWindows sneakely creates
1071 //a new menu item "Window" on the menu bar natively, without
1072 //notifying the actual wxMenuBar. Therefore, the Window
1073 //menu never go into the actual calculations...
1074 //So if a user tries to insert a menu after the Window menu
1075 //his/her calculations will be one(1) index off, since the
1076 //Window menu is before the to-be-removed menu and
1077 //wxMenuBar doesn't know about the existance of it.
1079 //There are two ways to deal with this -
1080 //1 - is to force the window menu to always be at the end
1081 //of the menu bar (rightmost, greatest index), I.E.
1082 //override remove and insert functions to force
1083 //the window (and help) menus to be at the rightmost positions
1084 //2 - is to increment pos here if the user is trying
1085 //to remove a menu after the Window menu
1087 //Solution #2 (which if chosen would go here)
1088 //is a little involved
1089 //1. Search for Window menu
1090 //2. If found note where it is
1091 //3. If the removal point is at or above where the Window
1095 //Case #2 is a MSW MDI "feature", where if a child MDI
1096 //frame is maximized, the system menu of the child MDI
1097 //frame is inserted at index 0 of the parent frame.
1099 //To deal with this we simply check to see if a child MDI
1100 //frame is maximized, then increment the position we
1101 //are going to remove the menu at.
1103 //Get a pointer to the children of the wxMDIParentFrame
1104 wxWindowList
* pParentsChildren
= &(GetFrame()->GetChildren());
1106 //Iterate through the children
1107 for (size_t n
= 0; n
< pParentsChildren
->GetCount(); ++n
)
1109 //Check to see if this particular child window is a
1111 if(pParentsChildren
->Item(n
)->GetData()->IsKindOf(CLASSINFO(wxMDIChildFrame
)))
1113 //If so then we need to see if it's maximized
1115 //Get a pointer to the child...
1116 wxMDIChildFrame
* pData
= (wxMDIChildFrame
*) pParentsChildren
->Item(n
)->GetData();
1119 if(pData
->IsMaximized())
1121 //Increase the removal position by one
1124 //Note that in Windows there can
1125 //Only be one maximized child window
1126 //(well not technically, but there
1127 //can only be one child system menu
1128 //prepended to the parent's menu
1129 //bar, which is what we're concerned about)
1132 }//end if child == wxMDIChildFrame
1133 }//end children iteration loop
1134 }//end if GetFrame()->IsKindOf(CLASSINFO(wxMDIParentFrame))
1135 #endif //wxUSE_MDI_ARCHITECTURE
1137 if ( !::RemoveMenu(GetHmenu(), (UINT
)pos
, MF_BYPOSITION
) )
1139 wxLogLastError(wxT("RemoveMenu"));
1143 if ( menu
->HasAccels() )
1145 // need to rebuild accell table
1146 RebuildAccelTable();
1148 #endif // wxUSE_ACCEL
1153 m_titles
.RemoveAt(arraypos
);
1160 void wxMenuBar::RebuildAccelTable()
1162 // merge the accelerators of all menus into one accel table
1163 size_t nAccelCount
= 0;
1164 size_t i
, count
= GetMenuCount();
1165 wxMenuList::iterator it
;
1166 for ( i
= 0, it
= m_menus
.begin(); i
< count
; i
++, it
++ )
1168 nAccelCount
+= (*it
)->GetAccelCount();
1173 wxAcceleratorEntry
*accelEntries
= new wxAcceleratorEntry
[nAccelCount
];
1176 for ( i
= 0, it
= m_menus
.begin(); i
< count
; i
++, it
++ )
1178 nAccelCount
+= (*it
)->CopyAccels(&accelEntries
[nAccelCount
]);
1181 m_accelTable
= wxAcceleratorTable(nAccelCount
, accelEntries
);
1183 delete [] accelEntries
;
1187 #endif // wxUSE_ACCEL
1189 void wxMenuBar::Attach(wxFrame
*frame
)
1191 wxMenuBarBase::Attach(frame
);
1194 RebuildAccelTable();
1195 #endif // wxUSE_ACCEL
1198 void wxMenuBar::Detach()
1200 wxMenuBarBase::Detach();
1203 #endif // wxUSE_MENUS