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