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