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