]> git.saurik.com Git - wxWidgets.git/blob - src/msw/menu.cpp
Some doc corrections (added blank lines at end of docs); corrected Forty sample
[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 m_menuCount = 0;
566 m_menus = NULL;
567 m_titles = NULL;
568 m_menuBarFrame = NULL;
569 m_hMenu = 0;
570 }
571
572 wxMenuBar::wxMenuBar( long WXUNUSED(style) )
573 {
574 m_eventHandler = this;
575 m_menuCount = 0;
576 m_menus = NULL;
577 m_titles = NULL;
578 m_menuBarFrame = NULL;
579 m_hMenu = 0;
580 }
581
582 wxMenuBar::wxMenuBar(int N, wxMenu *Menus[], const wxString Titles[])
583 {
584 m_eventHandler = this;
585 m_menuCount = N;
586 m_menus = Menus;
587 m_titles = new wxString[N];
588 int i;
589 for ( i = 0; i < N; i++ )
590 m_titles[i] = Titles[i];
591 m_menuBarFrame = NULL;
592 for (i = 0; i < N; i++)
593 m_menus[i]->m_menuBar = (wxMenuBar *) this;
594
595 m_hMenu = 0;
596 }
597
598 wxMenuBar::~wxMenuBar()
599 {
600 // In fact, don't want menu to be destroyed before MDI
601 // shuffling has taken place. Let it be destroyed
602 // automatically when the window is destroyed.
603
604 // DestroyMenu(menu);
605 // m_hMenu = NULL;
606
607 int i;
608 /*
609 // See remarks in ::~wxMenu() method
610 // BEWARE - this may interfere with MDI fixes, so
611 // may need to remove
612 int N = 0 ;
613
614 if (m_menuBarFrame && ((m_menuBarFrame->GetWindowStyleFlag() & wxSDI) == wxSDI))
615 {
616 if (menu)
617 N = GetMenuItemCount(menu) ;
618 for (i = N-1; i >= 0; i--)
619 RemoveMenu(menu, i, MF_BYPOSITION);
620 }
621 */
622 for (i = 0; i < m_menuCount; i++)
623 {
624 delete m_menus[i];
625 }
626 delete[] m_menus;
627 delete[] m_titles;
628
629 /* Don't destroy menu here, in case we're MDI and
630 need to do some shuffling with VALID menu handles.
631 if (menu)
632 DestroyMenu(menu);
633 m_hMenu = 0;
634 */
635 }
636
637 // Must only be used AFTER menu has been attached to frame,
638 // otherwise use individual menus to enable/disable items
639 void wxMenuBar::Enable(int Id, bool Flag)
640 {
641 int ms_flag;
642 if (Flag)
643 ms_flag = MF_ENABLED;
644 else
645 ms_flag = MF_GRAYED;
646
647 wxMenu *itemMenu = NULL;
648 wxMenuItem *item = FindItemForId(Id, &itemMenu) ;
649 if (!item)
650 return;
651
652 if (itemMenu->m_hMenu)
653 EnableMenuItem((HMENU)itemMenu->m_hMenu, Id, MF_BYCOMMAND | ms_flag);
654 else if (itemMenu->m_savehMenu)
655 EnableMenuItem((HMENU)itemMenu->m_savehMenu, Id, MF_BYCOMMAND | ms_flag);
656
657 }
658
659 void wxMenuBar::EnableTop(int pos, bool flag)
660 {
661 int ms_flag;
662 if (flag)
663 ms_flag = MF_ENABLED;
664 else
665 ms_flag = MF_GRAYED;
666
667 EnableMenuItem((HMENU)m_hMenu, pos, MF_BYPOSITION | ms_flag);
668 DrawMenuBar((HWND) m_menuBarFrame->GetHWND()) ;
669 }
670
671 // Must only be used AFTER menu has been attached to frame,
672 // otherwise use individual menus
673 void wxMenuBar::Check(int Id, bool Flag)
674 {
675 wxMenu *itemMenu = NULL;
676 wxMenuItem *item = FindItemForId(Id, &itemMenu) ;
677 if (!item)
678 return;
679
680 if (!item->IsCheckable())
681 return ;
682 int ms_flag;
683 if (Flag)
684 ms_flag = MF_CHECKED;
685 else
686 ms_flag = MF_UNCHECKED;
687
688 if (itemMenu->m_hMenu)
689 CheckMenuItem((HMENU)itemMenu->m_hMenu, Id, MF_BYCOMMAND | ms_flag);
690 else if (itemMenu->m_savehMenu)
691 CheckMenuItem((HMENU)itemMenu->m_savehMenu, Id, MF_BYCOMMAND | ms_flag);
692
693 // CheckMenuItem((HMENU)m_hMenu, Id, MF_BYCOMMAND | ms_flag);
694 }
695
696 bool wxMenuBar::Checked(int Id) const
697 {
698 wxMenu *itemMenu = NULL;
699 wxMenuItem *item = FindItemForId(Id, &itemMenu) ;
700 if (!item)
701 return FALSE;
702
703 int Flag = 0;
704
705 if (itemMenu->m_hMenu)
706 Flag=GetMenuState((HMENU)itemMenu->m_hMenu, Id, MF_BYCOMMAND) ;
707 else if (itemMenu->m_savehMenu)
708 Flag=GetMenuState((HMENU)itemMenu->m_savehMenu, Id, MF_BYCOMMAND) ;
709
710 // Flag=GetMenuState((HMENU)m_hMenu, Id, MF_BYCOMMAND) ;
711
712 if (Flag&MF_CHECKED)
713 return TRUE ;
714 else
715 return FALSE ;
716 }
717
718 bool wxMenuBar::Enabled(int Id) const
719 {
720 wxMenu *itemMenu = NULL;
721 wxMenuItem *item = FindItemForId(Id, &itemMenu) ;
722 if (!item)
723 return FALSE;
724
725 int Flag ;
726
727 if (itemMenu->m_hMenu)
728 Flag=GetMenuState((HMENU)itemMenu->m_hMenu, Id, MF_BYCOMMAND) ;
729 else if (itemMenu->m_savehMenu)
730 Flag=GetMenuState((HMENU)itemMenu->m_savehMenu, Id, MF_BYCOMMAND) ;
731
732 if (Flag&MF_ENABLED)
733 return TRUE ;
734 else
735 return FALSE ;
736 }
737
738
739 void wxMenuBar::SetLabel(int Id, const wxString& label)
740 {
741 wxMenu *itemMenu = NULL;
742 wxMenuItem *item = FindItemForId(Id, &itemMenu) ;
743
744 if (!item)
745 return;
746
747 if (itemMenu->m_hMenu)
748 {
749 UINT was_flag = GetMenuState((HMENU)itemMenu->m_hMenu,Id,MF_BYCOMMAND) ;
750 ModifyMenu((HMENU)itemMenu->m_hMenu,Id,MF_BYCOMMAND|MF_STRING|was_flag,Id,(const char *)label) ;
751 }
752 else if (itemMenu->m_savehMenu)
753 {
754 UINT was_flag = GetMenuState((HMENU)itemMenu->m_savehMenu,Id,MF_BYCOMMAND) ;
755 ModifyMenu((HMENU)itemMenu->m_savehMenu,Id,MF_BYCOMMAND|MF_STRING|was_flag,Id,(const char *)label) ;
756 }
757 }
758
759 wxString wxMenuBar::GetLabel(int Id) const
760 {
761 wxMenu *itemMenu = NULL;
762 wxMenuItem *item = FindItemForId(Id, &itemMenu) ;
763
764 if (!item)
765 return wxString("");
766
767 static char tmp[128] ;
768 int len = 0;
769 if (itemMenu->m_hMenu)
770 {
771 len = GetMenuString((HMENU)itemMenu->m_hMenu,Id,tmp,127,MF_BYCOMMAND) ;
772 }
773 else if (itemMenu->m_savehMenu)
774 {
775 len = GetMenuString((HMENU)itemMenu->m_savehMenu,Id,tmp,127,MF_BYCOMMAND) ;
776 }
777
778 // int len = GetMenuString((HMENU)m_hMenu,Id,tmp,127,MF_BYCOMMAND) ;
779 tmp[len] = '\0' ;
780 return wxString(tmp) ;
781 }
782
783 void wxMenuBar::SetLabelTop(int pos, const wxString& label)
784 {
785 UINT was_flag = GetMenuState((HMENU)m_hMenu,pos,MF_BYPOSITION) ;
786 if (was_flag&MF_POPUP)
787 {
788 was_flag &= 0xff ;
789 HMENU popup = GetSubMenu((HMENU)m_hMenu,pos) ;
790 ModifyMenu((HMENU)m_hMenu,pos,MF_BYPOSITION|MF_STRING|was_flag,(UINT)popup,(const char *)label) ;
791 }
792 else
793 ModifyMenu((HMENU)m_hMenu,pos,MF_BYPOSITION|MF_STRING|was_flag,pos,(const char *)label) ;
794 }
795
796 wxString wxMenuBar::GetLabelTop(int pos) const
797 {
798 static char tmp[128] ;
799 int len = GetMenuString((HMENU)m_hMenu,pos,tmp,127,MF_BYPOSITION) ;
800 tmp[len] = '\0' ;
801 return wxString(tmp);
802 }
803
804 bool wxMenuBar::OnDelete(wxMenu *a_menu, int pos)
805 {
806 if (!m_menuBarFrame)
807 return TRUE;
808
809 if (RemoveMenu((HMENU)m_hMenu, (UINT)pos, MF_BYPOSITION)) {
810 m_menus[pos]->m_hMenu = m_menus[pos]->m_savehMenu;
811 m_menus[pos]->m_savehMenu = 0;
812
813 if (m_menuBarFrame) {
814 DrawMenuBar((HWND) m_menuBarFrame->GetHWND()) ;
815 }
816
817 return TRUE;
818 }
819
820 return FALSE;
821 }
822
823 bool wxMenuBar::OnAppend(wxMenu *a_menu, const char *title)
824 {
825 if (!a_menu->m_hMenu)
826 return FALSE;
827
828 if (!m_menuBarFrame)
829 return TRUE;
830
831 a_menu->m_savehMenu = a_menu->m_hMenu;
832 a_menu->m_hMenu = 0;
833
834 AppendMenu((HMENU)m_hMenu, MF_POPUP | MF_STRING, (UINT)a_menu->m_savehMenu, title);
835
836 DrawMenuBar((HWND) m_menuBarFrame->GetHWND());
837
838 return TRUE;
839 }
840
841 void wxMenuBar::Append (wxMenu * menu, const wxString& title)
842 {
843 if (!OnAppend(menu, title))
844 return;
845
846 m_menuCount ++;
847 wxMenu **new_menus = new wxMenu *[m_menuCount];
848 wxString *new_titles = new wxString[m_menuCount];
849 int i;
850
851 for (i = 0; i < m_menuCount - 1; i++)
852 {
853 new_menus[i] = m_menus[i];
854 m_menus[i] = NULL;
855 new_titles[i] = m_titles[i];
856 m_titles[i] = "";
857 }
858 if (m_menus)
859 {
860 delete[]m_menus;
861 delete[]m_titles;
862 }
863 m_menus = new_menus;
864 m_titles = new_titles;
865
866 m_menus[m_menuCount - 1] = (wxMenu *)menu;
867 m_titles[m_menuCount - 1] = title;
868
869 ((wxMenu *)menu)->m_menuBar = (wxMenuBar *) this;
870 ((wxMenu *)menu)->SetParent(this);
871 }
872
873 void wxMenuBar::Delete(wxMenu * menu, int i)
874 {
875 int j;
876 int ii = (int) i;
877
878 if (menu != 0) {
879 for (ii = 0; ii < m_menuCount; ii++) {
880 if (m_menus[ii] == menu)
881 break;
882 }
883 if (ii >= m_menuCount)
884 return;
885 } else {
886 if (ii < 0 || ii >= m_menuCount)
887 return;
888 menu = m_menus[ii];
889 }
890
891 if (!OnDelete(menu, ii))
892 return;
893
894 menu->SetParent(NULL);
895
896 -- m_menuCount;
897 for (j = ii; j < m_menuCount; j++) {
898 m_menus[j] = m_menus[j + 1];
899 m_titles[j] = m_titles[j + 1];
900 }
901 }
902
903 // Find the menu menuString, item itemString, and return the item id.
904 // Returns -1 if none found.
905 int wxMenuBar::FindMenuItem (const wxString& menuString, const wxString& itemString) const
906 {
907 char buf1[200];
908 char buf2[200];
909 wxStripMenuCodes ((char *)(const char *)menuString, buf1);
910 int i;
911 for (i = 0; i < m_menuCount; i++)
912 {
913 wxStripMenuCodes ((char *)(const char *)m_titles[i], buf2);
914 if (strcmp (buf1, buf2) == 0)
915 return m_menus[i]->FindItem (itemString);
916 }
917 return -1;
918 }
919
920 wxMenuItem *wxMenuBar::FindItemForId (int Id, wxMenu ** itemMenu) const
921 {
922 if (itemMenu)
923 *itemMenu = NULL;
924
925 wxMenuItem *item = NULL;
926 int i;
927 for (i = 0; i < m_menuCount; i++)
928 {
929 item = m_menus[i]->FindItemForId (Id, itemMenu);
930 if (item)
931 return item;
932 }
933 return NULL;
934 }
935
936 void wxMenuBar::SetHelpString (int Id, const wxString& helpString)
937 {
938 int i;
939 for (i = 0; i < m_menuCount; i++)
940 {
941 if (m_menus[i]->FindItemForId (Id))
942 {
943 m_menus[i]->SetHelpString (Id, helpString);
944 return;
945 }
946 }
947 }
948
949 wxString wxMenuBar::GetHelpString (int Id) const
950 {
951 int i;
952 for (i = 0; i < m_menuCount; i++)
953 {
954 if (m_menus[i]->FindItemForId (Id))
955 return wxString(m_menus[i]->GetHelpString (Id));
956 }
957 return wxString("");
958 }
959
960 wxWindow *wxMenu::GetWindow() const
961 {
962 if ( m_pInvokingWindow != NULL )
963 return m_pInvokingWindow;
964 if ( m_menuBar != NULL)
965 return m_menuBar->m_menuBarFrame;
966 return NULL;
967 }
968
969 WXHMENU wxMenu::GetHMenu() const
970 {
971 if ( m_hMenu != 0 )
972 return m_hMenu;
973 else if ( m_savehMenu != 0 )
974 return m_savehMenu;
975
976 return 0;
977 }
978
979 // Update a menu and all submenus recursively.
980 // source is the object that has the update event handlers
981 // defined for it. If NULL, the menu or associated window
982 // will be used.
983 void wxMenu::UpdateUI(wxEvtHandler* source)
984 {
985 if (!source && GetInvokingWindow())
986 source = GetInvokingWindow()->GetEventHandler();
987 if (!source)
988 source = GetEventHandler();
989 if (!source)
990 source = this;
991
992 wxNode* node = GetItems().First();
993 while (node)
994 {
995 wxMenuItem* item = (wxMenuItem*) node->Data();
996 if ( !item->IsSeparator() )
997 {
998 wxWindowID id = item->GetId();
999 wxUpdateUIEvent event(id);
1000 event.SetEventObject( source );
1001
1002 if (source->ProcessEvent(event))
1003 {
1004 if (event.GetSetText())
1005 SetLabel(id, event.GetText());
1006 if (event.GetSetChecked())
1007 Check(id, event.GetChecked());
1008 if (event.GetSetEnabled())
1009 Enable(id, event.GetEnabled());
1010 }
1011
1012 if (item->GetSubMenu())
1013 item->GetSubMenu()->UpdateUI(source);
1014 }
1015 node = node->Next();
1016 }
1017 }