]> git.saurik.com Git - wxWidgets.git/blob - src/msw/menu.cpp
1. corrected (but the fix is ugly) the multiple def button problem
[wxWidgets.git] / src / msw / menu.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: menu.cpp
3 // Purpose: wxMenu, wxMenuBar, wxMenuItem
4 // Author: Julian Smart
5 // Modified by: Vadim Zeitlin
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ===========================================================================
13 // declarations
14 // ===========================================================================
15
16 // ---------------------------------------------------------------------------
17 // headers
18 // ---------------------------------------------------------------------------
19
20 #ifdef __GNUG__
21 #pragma implementation "menu.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28 #pragma hdrstop
29 #endif
30
31 #ifndef WX_PRECOMP
32 #include "wx/frame.h"
33 #include "wx/menu.h"
34 #include "wx/utils.h"
35 #include "wx/intl.h"
36 #endif
37
38 #if wxUSE_OWNER_DRAWN
39 #include "wx/ownerdrw.h"
40 #endif
41
42 #include "wx/msw/private.h"
43 #include "wx/msw/menu.h"
44 #include "wx/menuitem.h"
45 #include "wx/log.h"
46
47 // other standard headers
48 #include <string.h>
49
50 // ----------------------------------------------------------------------------
51 // global variables
52 // ----------------------------------------------------------------------------
53
54 extern wxMenu *wxCurrentPopupMenu;
55
56 // ----------------------------------------------------------------------------
57 // constants
58 // ----------------------------------------------------------------------------
59
60 // the (popup) menu title has this special id
61 static const int idMenuTitle = -2;
62
63 // ----------------------------------------------------------------------------
64 // macros
65 // ----------------------------------------------------------------------------
66
67 #if !USE_SHARED_LIBRARY
68 IMPLEMENT_DYNAMIC_CLASS(wxMenu, wxEvtHandler)
69 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxEvtHandler)
70 #endif
71
72 // ============================================================================
73 // implementation
74 // ============================================================================
75
76 // ---------------------------------------------------------------------------
77 // wxMenu construction, adding and removing menu items
78 // ---------------------------------------------------------------------------
79
80 // Construct a menu with optional title (then use append)
81 void wxMenu::Init(const wxString& title, const wxFunction func )
82 {
83 m_title = title;
84 m_eventHandler = this;
85 m_pInvokingWindow = NULL;
86 m_doBreak = FALSE;
87 m_noItems = 0;
88 m_menuBar = NULL;
89 m_hMenu = (WXHMENU) CreatePopupMenu();
90 m_savehMenu = 0;
91 m_topLevelMenu = this;
92 m_clientData = (void*) NULL;
93
94 if ( !!m_title )
95 {
96 Append(idMenuTitle, m_title);
97 AppendSeparator();
98 }
99
100 Callback(func);
101 }
102
103 // The wxWindow destructor will take care of deleting the submenus.
104 wxMenu::~wxMenu()
105 {
106 // free Windows resources
107 if ( m_hMenu )
108 {
109 if ( !::DestroyMenu(GetHmenu()) )
110 {
111 wxLogLastError("DestroyMenu");
112 }
113 }
114
115 // delete submenus
116 wxNode *node = m_menuItems.First();
117 while ( node )
118 {
119 wxMenuItem *item = (wxMenuItem *)node->Data();
120
121 // Delete child menus.
122 // Beware: they must not be appended to children list!!!
123 // (because order of delete is significant)
124 if ( item->IsSubMenu() )
125 item->DeleteSubMenu();
126
127 wxNode *next = node->Next();
128 delete item;
129 delete node;
130 node = next;
131 }
132
133 #if wxUSE_ACCEL
134 // delete accels
135 WX_CLEAR_ARRAY(m_accels);
136 #endif // wxUSE_ACCEL
137 }
138
139 void wxMenu::Break()
140 {
141 m_doBreak = TRUE;
142 }
143
144 // function appends a new item or submenu to the menu
145 void wxMenu::Append(wxMenuItem *pItem)
146 {
147 wxCHECK_RET( pItem != NULL, wxT("can't append NULL item to the menu") );
148
149 #if wxUSE_ACCEL
150 wxAcceleratorEntry *accel = wxGetAccelFromString(pItem->GetText());
151 if ( accel ) {
152 m_accels.Add(accel);
153 accel->m_command = pItem->GetId();
154 }
155 #endif // wxUSE_ACCEL
156
157 UINT flags = 0;
158
159 // if "Break" has just been called, insert a menu break before this item
160 // (and don't forget to reset the flag)
161 if ( m_doBreak ) {
162 flags |= MF_MENUBREAK;
163 m_doBreak = FALSE;
164 }
165
166 if ( pItem->IsSeparator() ) {
167 flags |= MF_SEPARATOR;
168 }
169
170 // id is the numeric id for normal menu items and HMENU for submenus as
171 // required by ::AppendMenu() API
172 UINT id;
173 wxMenu *submenu = pItem->GetSubMenu();
174 if ( submenu != NULL ) {
175 wxASSERT( submenu->GetHMenu() != (WXHMENU) NULL );
176
177 id = (UINT)submenu->GetHMenu();
178 submenu->m_topLevelMenu = m_topLevelMenu;
179 submenu->m_savehMenu = (WXHMENU)id;
180 submenu->m_hMenu = 0;
181
182 flags |= MF_POPUP;
183 }
184 else {
185 id = pItem->GetId();
186 }
187
188 LPCTSTR pData;
189
190 #if wxUSE_OWNER_DRAWN
191 if ( pItem->IsOwnerDrawn() ) { // want to get {Measure|Draw}Item messages?
192 // item draws itself, pass pointer to it in data parameter
193 flags |= MF_OWNERDRAW;
194 pData = (LPCTSTR)pItem;
195 }
196 else
197 #endif
198 {
199 // menu is just a normal string (passed in data parameter)
200 flags |= MF_STRING;
201
202 pData = (char*)pItem->GetText().c_str();
203 }
204
205 if ( !::AppendMenu(GetHmenu(), flags, id, pData) )
206 {
207 wxLogLastError("AppendMenu");
208 }
209 else
210 {
211 #ifdef __WIN32__
212 if ( (int)id == idMenuTitle )
213 {
214 // visually select the menu title
215 MENUITEMINFO mii;
216 mii.cbSize = sizeof(mii);
217 mii.fMask = MIIM_STATE;
218 mii.fState = MFS_DEFAULT;
219
220 if ( !SetMenuItemInfo(GetHmenu(), (unsigned)id, FALSE, &mii) )
221 {
222 wxLogLastError(wxT("SetMenuItemInfo"));
223 }
224 }
225 #endif // __WIN32__
226
227 m_menuItems.Append(pItem);
228 m_noItems++;
229 }
230 }
231
232 void wxMenu::AppendSeparator()
233 {
234 Append(new wxMenuItem(this, ID_SEPARATOR));
235 }
236
237 // Pullright item
238 void wxMenu::Append(int id,
239 const wxString& label,
240 wxMenu *SubMenu,
241 const wxString& helpString)
242 {
243 Append(new wxMenuItem(this, id, label, helpString, FALSE, SubMenu));
244 }
245
246 // Ordinary menu item
247 void wxMenu::Append(int id,
248 const wxString& label,
249 const wxString& helpString,
250 bool checkable)
251 {
252 // 'checkable' parameter is useless for Windows.
253 Append(new wxMenuItem(this, id, label, helpString, checkable));
254 }
255
256 // delete item by id
257 void wxMenu::Delete(int id)
258 {
259 wxMenuItem *item = NULL;
260 int pos;
261 wxNode *node;
262 for (pos = 0, node = m_menuItems.First(); node; node = node->Next(), pos++)
263 {
264 item = (wxMenuItem *)node->Data();
265 if ( item->GetId() == id )
266 break;
267 }
268
269 wxCHECK_RET( node, wxT("wxMenu::Delete(): item doesn't exist") );
270
271 HMENU menu = GetHmenu();
272
273 wxMenu *pSubMenu = item->GetSubMenu();
274 if ( pSubMenu != NULL ) {
275 RemoveMenu(menu, (UINT)pos, MF_BYPOSITION);
276 pSubMenu->m_hMenu = pSubMenu->m_savehMenu;
277 pSubMenu->m_savehMenu = 0;
278 // RemoveChild(item->subMenu);
279 pSubMenu->m_topLevelMenu = NULL;
280 // TODO: Why isn't subMenu deleted here???
281 // Will put this in for now. Assuming this is supposed
282 // to delete the menu, not just remove it.
283 item->DeleteSubMenu();
284 }
285 else {
286 DeleteMenu(menu, (UINT)pos, MF_BYPOSITION);
287 }
288
289 m_menuItems.DeleteNode(node);
290 delete item;
291 }
292
293 #if wxUSE_ACCEL
294
295 // ---------------------------------------------------------------------------
296 // accelerator helpers
297 // ---------------------------------------------------------------------------
298
299 // create the wxAcceleratorEntries for our accels and put them into provided
300 // array - return the number of accels we have
301 size_t wxMenu::CopyAccels(wxAcceleratorEntry *accels) const
302 {
303 size_t count = GetAccelCount();
304 for ( size_t n = 0; n < count; n++ )
305 {
306 *accels++ = *m_accels[n];
307 }
308
309 return count;
310 }
311
312 #endif // wxUSE_ACCEL
313
314 // ---------------------------------------------------------------------------
315 // wxMenu functions implemented in wxMenuItem
316 // ---------------------------------------------------------------------------
317
318 void wxMenu::Enable(int id, bool Flag)
319 {
320 wxMenuItem *item = FindItemForId(id);
321 wxCHECK_RET( item != NULL, wxT("can't enable non-existing menu item") );
322
323 item->Enable(Flag);
324 }
325
326 bool wxMenu::IsEnabled(int id) const
327 {
328 wxMenuItem *item = FindItemForId(id);
329 wxCHECK_MSG( item != NULL, FALSE, wxT("invalid item id") );
330
331 return item->IsEnabled();
332 }
333
334 void wxMenu::Check(int id, bool Flag)
335 {
336 wxMenuItem *item = FindItemForId(id);
337 wxCHECK_RET( item != NULL, wxT("can't get status of non-existing menu item") );
338
339 item->Check(Flag);
340 }
341
342 bool wxMenu::IsChecked(int id) const
343 {
344 wxMenuItem *item = FindItemForId(id);
345 wxCHECK_MSG( item != NULL, FALSE, wxT("invalid item id") );
346
347 return item->IsChecked();
348 }
349
350 void wxMenu::SetLabel(int id, const wxString& label)
351 {
352 wxMenuItem *item = FindItemForId(id);
353 wxCHECK_RET( item, wxT("wxMenu::SetLabel: no such item") );
354
355 item->SetText(label);
356 }
357
358 wxString wxMenu::GetLabel(int id) const
359 {
360 wxString label;
361 wxMenuItem *pItem = FindItemForId(id);
362 if (pItem)
363 label = pItem->GetText();
364 else
365 wxFAIL_MSG(wxT("wxMenu::GetLabel: item doesn't exist"));
366
367 return label;
368 }
369
370 void wxMenu::SetHelpString(int itemId, const wxString& helpString)
371 {
372 wxMenuItem *item = FindItemForId (itemId);
373 if (item)
374 item->SetHelp(helpString);
375 else
376 wxFAIL_MSG(wxT("wxMenu::SetHelpString: item doesn't exist"));
377 }
378
379 wxString wxMenu::GetHelpString (int itemId) const
380 {
381 wxString help;
382 wxMenuItem *item = FindItemForId (itemId);
383 if (item)
384 help = item->GetHelp();
385 else
386 wxFAIL_MSG(wxT("wxMenu::GetHelpString: item doesn't exist"));
387
388 return help;
389 }
390
391 // ---------------------------------------------------------------------------
392 // wxMenu title
393 // ---------------------------------------------------------------------------
394
395 void wxMenu::SetTitle(const wxString& label)
396 {
397 bool hasNoTitle = m_title.IsEmpty();
398 m_title = label;
399
400 HMENU hMenu = GetHmenu();
401
402 if ( hasNoTitle )
403 {
404 if ( !label.IsEmpty() )
405 {
406 if ( !InsertMenu(hMenu, 0u, MF_BYPOSITION | MF_STRING,
407 (unsigned)idMenuTitle, m_title) ||
408 !InsertMenu(hMenu, 1u, MF_BYPOSITION, (unsigned)-1, NULL) )
409 {
410 wxLogLastError(wxT("InsertMenu"));
411 }
412 }
413 }
414 else
415 {
416 if ( label.IsEmpty() )
417 {
418 // remove the title and the separator after it
419 if ( !RemoveMenu(hMenu, 0, MF_BYPOSITION) ||
420 !RemoveMenu(hMenu, 0, MF_BYPOSITION) )
421 {
422 wxLogLastError("RemoveMenu");
423 }
424 }
425 else
426 {
427 // modify the title
428 if ( !ModifyMenu(hMenu, 0u,
429 MF_BYPOSITION | MF_STRING,
430 (unsigned)idMenuTitle, m_title) )
431 {
432 wxLogLastError("ModifyMenu");
433 }
434 }
435 }
436
437 #ifdef __WIN32__
438 // put the title string in bold face
439 if ( !m_title.IsEmpty() )
440 {
441 MENUITEMINFO mii;
442 mii.cbSize = sizeof(mii);
443 mii.fMask = MIIM_STATE;
444 mii.fState = MFS_DEFAULT;
445
446 if ( !SetMenuItemInfo(hMenu, (unsigned)idMenuTitle, FALSE, &mii) )
447 {
448 wxLogLastError("SetMenuItemInfo");
449 }
450 }
451 #endif
452 }
453
454 const wxString wxMenu::GetTitle() const
455 {
456 return m_title;
457 }
458
459 // ---------------------------------------------------------------------------
460 // event processing
461 // ---------------------------------------------------------------------------
462
463 bool wxMenu::MSWCommand(WXUINT WXUNUSED(param), WXWORD id)
464 {
465 // ignore commands from the menu title
466
467 // NB: VC++ generates wrong assembler for `if ( id != idMenuTitle )'!!
468 if ( id != (WXWORD)idMenuTitle )
469 {
470 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED);
471 event.SetEventObject( this );
472 event.SetId( id );
473 event.SetInt( id );
474 ProcessCommand(event);
475 }
476
477 return TRUE;
478 }
479
480 bool wxMenu::ProcessCommand(wxCommandEvent & event)
481 {
482 bool processed = FALSE;
483
484 // Try a callback
485 if (m_callback)
486 {
487 (void)(*(m_callback))(*this, event);
488 processed = TRUE;
489 }
490
491 // Try the menu's event handler
492 if ( !processed && GetEventHandler())
493 {
494 processed = GetEventHandler()->ProcessEvent(event);
495 }
496
497 // Try the window the menu was popped up from (and up through the
498 // hierarchy)
499 wxWindow *win = GetInvokingWindow();
500 if ( !processed && win )
501 processed = win->GetEventHandler()->ProcessEvent(event);
502
503 return processed;
504 }
505
506 // ---------------------------------------------------------------------------
507 // Item search
508 // ---------------------------------------------------------------------------
509
510 // Finds the item id matching the given string, -1 if not found.
511 int wxMenu::FindItem (const wxString& itemString) const
512 {
513 wxString itemLabel = wxStripMenuCodes(itemString);
514 for ( wxNode *node = m_menuItems.First(); node; node = node->Next() )
515 {
516 wxMenuItem *item = (wxMenuItem *)node->Data();
517 if ( item->IsSubMenu() )
518 {
519 int ans = item->GetSubMenu()->FindItem(itemString);
520 if ( ans != wxNOT_FOUND )
521 return ans;
522 }
523 else if ( !item->IsSeparator() )
524 {
525 wxString label = wxStripMenuCodes(item->GetText());
526 if ( itemLabel == label )
527 return item->GetId();
528 }
529 }
530
531 return wxNOT_FOUND;
532 }
533
534 wxMenuItem *wxMenu::FindItemForId(int itemId, wxMenu ** itemMenu) const
535 {
536 if ( itemMenu )
537 *itemMenu = NULL;
538
539 wxMenuItem *item = NULL;
540 for ( wxNode *node = m_menuItems.First(); node && !item; node = node->Next() )
541 {
542 item = (wxMenuItem *)node->Data();
543
544 if ( item->GetId() == itemId )
545 {
546 if (itemMenu)
547 *itemMenu = (wxMenu *)this;
548 }
549 else if ( item->IsSubMenu() )
550 {
551 item = item->GetSubMenu()->FindItemForId(itemId, itemMenu);
552 }
553 else
554 {
555 // don't exit the loop
556 item = NULL;
557 }
558 }
559
560 return item;
561 }
562
563 // ---------------------------------------------------------------------------
564 // other
565 // ---------------------------------------------------------------------------
566
567 void wxMenu::Attach(wxMenuBar *menubar)
568 {
569 // menu can be in at most one menubar because otherwise they would both
570 // delete the menu pointer
571 wxASSERT_MSG( !m_menuBar, wxT("menu belongs to 2 menubars, expect a crash") );
572
573 m_menuBar = menubar;
574 m_savehMenu = m_hMenu;
575 m_hMenu = 0;
576 }
577
578 void wxMenu::Detach()
579 {
580 wxASSERT_MSG( m_menuBar, wxT("can't detach menu if it's not attached") );
581
582 m_menuBar = NULL;
583 m_hMenu = m_savehMenu;
584 m_savehMenu = 0;
585 }
586
587 // ---------------------------------------------------------------------------
588 // Menu Bar
589 // ---------------------------------------------------------------------------
590
591 void wxMenuBar::Init()
592 {
593 m_eventHandler = this;
594 m_menuBarFrame = NULL;
595 m_hMenu = 0;
596 }
597
598 wxMenuBar::wxMenuBar()
599 {
600 Init();
601 }
602
603 wxMenuBar::wxMenuBar( long WXUNUSED(style) )
604 {
605 Init();
606 }
607
608 wxMenuBar::wxMenuBar(int count, wxMenu *menus[], const wxString titles[])
609 {
610 Init();
611
612 m_titles.Alloc(count);
613
614 for ( int i = 0; i < count; i++ )
615 {
616 m_menus.Append(menus[i]);
617 m_titles.Add(titles[i]);
618
619 menus[i]->Attach(this);
620 }
621 }
622
623 wxMenuBar::~wxMenuBar()
624 {
625 }
626
627 // ---------------------------------------------------------------------------
628 // wxMenuBar helpers
629 // ---------------------------------------------------------------------------
630
631 void wxMenuBar::Refresh()
632 {
633 wxCHECK_RET( IsAttached(), wxT("can't refresh unatteched menubar") );
634
635 DrawMenuBar(GetHwndOf(m_menuBarFrame));
636 }
637
638 WXHMENU wxMenuBar::Create()
639 {
640 if (m_hMenu != 0 )
641 return m_hMenu;
642
643 wxCHECK_MSG( !m_hMenu, TRUE, wxT("menubar already created") );
644
645 m_hMenu = (WXHMENU)::CreateMenu();
646
647 if ( !m_hMenu )
648 {
649 wxLogLastError("CreateMenu");
650 }
651 else
652 {
653 size_t count = GetMenuCount();
654 for ( size_t i = 0; i < count; i++ )
655 {
656 if ( !::AppendMenu((HMENU)m_hMenu, MF_POPUP | MF_STRING,
657 (UINT)m_menus[i]->GetHMenu(),
658 m_titles[i]) )
659 {
660 wxLogLastError("AppendMenu");
661 }
662 }
663 }
664
665 return m_hMenu;
666 }
667
668 // ---------------------------------------------------------------------------
669 // wxMenuBar functions to work with the top level submenus
670 // ---------------------------------------------------------------------------
671
672 // NB: we don't support owner drawn top level items for now, if we do these
673 // functions would have to be changed to use wxMenuItem as well
674
675 void wxMenuBar::EnableTop(size_t pos, bool enable)
676 {
677 int flag = enable ? MF_ENABLED : MF_GRAYED;;
678
679 EnableMenuItem((HMENU)m_hMenu, pos, MF_BYPOSITION | flag);
680
681 Refresh();
682 }
683
684 void wxMenuBar::SetLabelTop(size_t pos, const wxString& label)
685 {
686 UINT id;
687 UINT flagsOld = ::GetMenuState((HMENU)m_hMenu, pos, MF_BYPOSITION);
688 if ( flagsOld == 0xFFFFFFFF )
689 {
690 wxLogLastError(wxT("GetMenuState"));
691
692 return;
693 }
694
695 if ( flagsOld & MF_POPUP )
696 {
697 // HIBYTE contains the number of items in the submenu in this case
698 flagsOld &= 0xff;
699 id = (UINT)::GetSubMenu((HMENU)m_hMenu, pos);
700 }
701 else
702 {
703 id = pos;
704 }
705
706 if ( ::ModifyMenu(GetHmenu(), pos, MF_BYPOSITION | MF_STRING | flagsOld,
707 id, label) == (int)0xFFFFFFFF )
708 {
709 wxLogLastError("ModifyMenu");
710 }
711 }
712
713 wxString wxMenuBar::GetLabelTop(size_t pos) const
714 {
715 int len = ::GetMenuString((HMENU)m_hMenu, pos, NULL, 0, MF_BYCOMMAND);
716
717 len++; // for the NUL character
718 wxString label;
719 ::GetMenuString(GetHmenu(), pos, label.GetWriteBuf(len), len, MF_BYCOMMAND);
720 label.UngetWriteBuf();
721
722 return label;
723 }
724
725 int wxMenuBar::FindMenu(const wxString& title)
726 {
727 wxString menuTitle = wxStripMenuCodes(title);
728
729 size_t count = GetMenuCount();
730 for ( size_t i = 0; i < count; i++ )
731 {
732 wxString title = wxStripMenuCodes(m_titles[i]);
733 if ( menuTitle == title )
734 return i;
735 }
736
737 return wxNOT_FOUND;
738
739 }
740
741 // ---------------------------------------------------------------------------
742 // wxMenuBar construction
743 // ---------------------------------------------------------------------------
744
745 wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title)
746 {
747 wxMenu *menuOld = wxMenuBarBase::Replace(pos, menu, title);
748 if ( !menuOld )
749 return FALSE;
750 m_titles[pos] = title;
751
752 if ( IsAttached() )
753 {
754 // can't use ModifyMenu() because it deletes the submenu it replaces
755 if ( !::RemoveMenu(GetHmenu(), (UINT)pos, MF_BYPOSITION) )
756 {
757 wxLogLastError("RemoveMenu");
758 }
759
760 if ( !::InsertMenu(GetHmenu(), (UINT)pos,
761 MF_BYPOSITION | MF_POPUP | MF_STRING,
762 (UINT)GetHmenuOf(menu), title) )
763 {
764 wxLogLastError("InsertMenu");
765 }
766
767 Refresh();
768 }
769
770 return menuOld;
771 }
772
773 bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title)
774 {
775 if ( !wxMenuBarBase::Insert(pos, menu, title) )
776 return FALSE;
777
778 m_titles.Insert(title, pos);
779
780 menu->Attach(this);
781
782 if ( IsAttached() )
783 {
784 if ( !::InsertMenu(GetHmenu(), pos,
785 MF_BYPOSITION | MF_POPUP | MF_STRING,
786 (UINT)GetHmenuOf(menu), title) )
787 {
788 wxLogLastError("InsertMenu");
789 }
790
791 Refresh();
792 }
793
794 return TRUE;
795 }
796
797 bool wxMenuBar::Append(wxMenu *menu, const wxString& title)
798 {
799 WXHMENU submenu = menu ? menu->GetHMenu() : 0;
800 wxCHECK_MSG( submenu, FALSE, wxT("can't append invalid menu to menubar") );
801
802 menu->Attach(this);
803
804 if ( IsAttached() )
805 {
806 if ( !::AppendMenu(GetHmenu(), MF_POPUP | MF_STRING,
807 (UINT)submenu, title) )
808 {
809 wxLogLastError(wxT("AppendMenu"));
810 }
811
812 Refresh();
813 }
814
815 wxMenuBarBase::Append(menu, title);
816
817 m_titles.Add(title);
818
819 return TRUE;
820 }
821
822 wxMenu *wxMenuBar::Remove(size_t pos)
823 {
824 wxMenu *menu = wxMenuBarBase::Remove(pos);
825 if ( !menu )
826 return NULL;
827
828 if ( IsAttached() )
829 {
830 if ( !::RemoveMenu(GetHmenu(), (UINT)pos, MF_BYPOSITION) )
831 {
832 wxLogLastError("RemoveMenu");
833 }
834
835 menu->Detach();
836
837 Refresh();
838 }
839
840 m_titles.Remove(pos);
841
842 return menu;
843 }
844
845 void wxMenuBar::Attach(wxFrame *frame)
846 {
847 wxASSERT_MSG( !IsAttached(), wxT("menubar already attached!") );
848
849 m_menuBarFrame = frame;
850
851 #if wxUSE_ACCEL
852 // create the accel table - we consider that the menubar construction is
853 // finished
854 size_t nAccelCount = 0;
855 size_t i, count = GetMenuCount();
856 for ( i = 0; i < count; i++ )
857 {
858 nAccelCount += m_menus[i]->GetAccelCount();
859 }
860
861 if ( nAccelCount )
862 {
863 wxAcceleratorEntry *accelEntries = new wxAcceleratorEntry[nAccelCount];
864
865 nAccelCount = 0;
866 for ( i = 0; i < count; i++ )
867 {
868 nAccelCount += m_menus[i]->CopyAccels(&accelEntries[nAccelCount]);
869 }
870
871 m_accelTable = wxAcceleratorTable(nAccelCount, accelEntries);
872
873 delete [] accelEntries;
874 }
875 #endif // wxUSE_ACCEL
876 }
877
878 void wxMenuBar::Detach()
879 {
880 // ::DestroyMenu((HMENU)m_hMenu);
881 m_hMenu = (WXHMENU)NULL;
882 m_menuBarFrame = NULL;
883 }
884
885
886 // ---------------------------------------------------------------------------
887 // wxMenuBar searching for menu items
888 // ---------------------------------------------------------------------------
889
890 // Find the itemString in menuString, and return the item id or wxNOT_FOUND
891 int wxMenuBar::FindMenuItem(const wxString& menuString,
892 const wxString& itemString) const
893 {
894 wxString menuLabel = wxStripMenuCodes(menuString);
895 size_t count = GetMenuCount();
896 for ( size_t i = 0; i < count; i++ )
897 {
898 wxString title = wxStripMenuCodes(m_titles[i]);
899 if ( menuString == title )
900 return m_menus[i]->FindItem(itemString);
901 }
902
903 return wxNOT_FOUND;
904 }
905
906 wxMenuItem *wxMenuBar::FindItem(int id, wxMenu **itemMenu) const
907 {
908 if ( itemMenu )
909 *itemMenu = NULL;
910
911 wxMenuItem *item = NULL;
912 size_t count = GetMenuCount();
913 for ( size_t i = 0; !item && (i < count); i++ )
914 {
915 item = m_menus[i]->FindItemForId(id, itemMenu);
916 }
917
918 return item;
919 }
920
921
922 // ----------------------------------------------------------------------------
923 // helper functions
924 // ----------------------------------------------------------------------------
925
926 wxWindow *wxMenu::GetWindow() const
927 {
928 if ( m_pInvokingWindow != NULL )
929 return m_pInvokingWindow;
930 else if ( m_menuBar != NULL)
931 return m_menuBar->GetFrame();
932
933 return NULL;
934 }
935
936 WXHMENU wxMenu::GetHMenu() const
937 {
938 if ( m_hMenu != 0 )
939 return m_hMenu;
940 else if ( m_savehMenu != 0 )
941 return m_savehMenu;
942
943 wxFAIL_MSG(wxT("wxMenu without HMENU"));
944
945 return 0;
946 }
947
948 // Update a menu and all submenus recursively. source is the object that has
949 // the update event handlers defined for it. If NULL, the menu or associated
950 // window will be used.
951 void wxMenu::UpdateUI(wxEvtHandler* source)
952 {
953 if (!source && GetInvokingWindow())
954 source = GetInvokingWindow()->GetEventHandler();
955 if (!source)
956 source = GetEventHandler();
957 if (!source)
958 source = this;
959
960 wxNode* node = GetItems().First();
961 while (node)
962 {
963 wxMenuItem* item = (wxMenuItem*) node->Data();
964 if ( !item->IsSeparator() )
965 {
966 wxWindowID id = item->GetId();
967 wxUpdateUIEvent event(id);
968 event.SetEventObject( source );
969
970 if (source->ProcessEvent(event))
971 {
972 if (event.GetSetText())
973 SetLabel(id, event.GetText());
974 if (event.GetSetChecked())
975 Check(id, event.GetChecked());
976 if (event.GetSetEnabled())
977 Enable(id, event.GetEnabled());
978 }
979
980 if (item->GetSubMenu())
981 item->GetSubMenu()->UpdateUI(source);
982 }
983 node = node->Next();
984 }
985 }