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