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