]> git.saurik.com Git - wxWidgets.git/blob - src/msw/menu.cpp
wxProcess-related code now works
[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 // put the title string in bold face
345 if ( !m_title.IsEmpty() )
346 {
347 MENUITEMINFO mii;
348 mii.cbSize = sizeof(mii);
349 mii.fMask = MIIM_STATE;
350 mii.fState = MFS_DEFAULT;
351
352 if ( !SetMenuItemInfo(hMenu, (unsigned)idMenuTitle, FALSE, &mii) )
353 {
354 wxLogLastError("SetMenuItemInfo");
355 }
356 }
357 }
358
359 const wxString wxMenu::GetTitle() const
360 {
361 return m_title;
362 }
363
364 void wxMenu::SetLabel(int Id, const wxString& label)
365 {
366 wxMenuItem *item = FindItemForId(Id) ;
367 if (item==NULL)
368 return;
369
370 if (item->GetSubMenu()==NULL)
371 {
372 if (m_hMenu)
373 {
374 UINT was_flag = GetMenuState((HMENU)m_hMenu,Id,MF_BYCOMMAND) ;
375 ModifyMenu((HMENU)m_hMenu,Id,MF_BYCOMMAND|MF_STRING|was_flag,Id,(const char *)label) ;
376 }
377 else if (m_savehMenu)
378 {
379 UINT was_flag = GetMenuState((HMENU)m_savehMenu,Id,MF_BYCOMMAND) ;
380 ModifyMenu((HMENU)m_savehMenu,Id,MF_BYCOMMAND|MF_STRING|was_flag,Id,(const char *)label) ;
381 }
382 }
383 else
384 {
385 wxMenu *father = item->GetSubMenu()->m_topLevelMenu ;
386 wxNode *node = father->m_menuItems.First() ;
387 int i = 0 ;
388 while (node)
389 {
390 wxMenuItem *matched = (wxMenuItem*)node->Data() ;
391 if (matched==item)
392 break ;
393 i++ ;
394 node = node->Next() ;
395 }
396 // Here, we have the position.
397 ModifyMenu((HMENU)father->m_savehMenu,i,
398 MF_BYPOSITION|MF_STRING|MF_POPUP,
399 (UINT)item->GetSubMenu()->m_savehMenu,(const char *)label) ;
400 }
401 item->SetName(label);
402 }
403
404 wxString wxMenu::GetLabel(int id) const
405 {
406 /*
407 static char tmp[128] ;
408 int len;
409 if (m_hMenu)
410 len = GetMenuString((HMENU)m_hMenu,Id,tmp,WXSIZEOF(tmp) - 1,MF_BYCOMMAND);
411 else if (m_savehMenu)
412 len = GetMenuString((HMENU)m_savehMenu,Id,tmp,WXSIZEOF(tmp) - 1,MF_BYCOMMAND);
413 else
414 len = 0 ;
415 tmp[len] = '\0' ;
416 return wxString(tmp) ;
417
418 */
419 wxMenuItem *pItem = FindItemForId(id) ;
420 if (pItem)
421 return pItem->GetName() ;
422 else
423 return wxEmptyString;
424 }
425
426 bool wxMenu::MSWCommand(WXUINT WXUNUSED(param), WXWORD id)
427 {
428 // ignore commands from the menu title
429
430 // NB: VC++ generates wrong assembler for `if ( id != idMenuTitle )'!!
431 if ( id != (WXWORD)idMenuTitle )
432 {
433 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED);
434 event.SetEventObject( this );
435 event.SetId( id );
436 event.SetInt( id );
437 ProcessCommand(event);
438 }
439
440 return TRUE;
441 }
442
443 // Finds the item id matching the given string, -1 if not found.
444 int wxMenu::FindItem (const wxString& itemString) const
445 {
446 char buf1[200];
447 char buf2[200];
448 wxStripMenuCodes ((char *)(const char *)itemString, buf1);
449
450 for (wxNode * node = m_menuItems.First (); node; node = node->Next ())
451 {
452 wxMenuItem *item = (wxMenuItem *) node->Data ();
453 if (item->GetSubMenu())
454 {
455 int ans = item->GetSubMenu()->FindItem(itemString);
456 if (ans > -1)
457 return ans;
458 }
459 if ( !item->IsSeparator() )
460 {
461 wxStripMenuCodes((char *)item->GetName().c_str(), buf2);
462 if (strcmp(buf1, buf2) == 0)
463 return item->GetId();
464 }
465 }
466
467 return -1;
468 }
469
470 wxMenuItem *wxMenu::FindItemForId(int itemId, wxMenu ** itemMenu) const
471 {
472 if (itemMenu)
473 *itemMenu = NULL;
474 for (wxNode * node = m_menuItems.First (); node; node = node->Next ())
475 {
476 wxMenuItem *item = (wxMenuItem *) node->Data ();
477
478 if (item->GetId() == itemId)
479 {
480 if (itemMenu)
481 *itemMenu = (wxMenu *) this;
482 return item;
483 }
484
485 if (item->GetSubMenu())
486 {
487 wxMenuItem *ans = item->GetSubMenu()->FindItemForId (itemId, itemMenu);
488 if (ans)
489 return ans;
490 }
491 }
492
493 if (itemMenu)
494 *itemMenu = NULL;
495 return NULL;
496 }
497
498 void wxMenu::SetHelpString(int itemId, const wxString& helpString)
499 {
500 wxMenuItem *item = FindItemForId (itemId);
501 if (item)
502 item->SetHelp(helpString);
503 }
504
505 wxString wxMenu::GetHelpString (int itemId) const
506 {
507 wxMenuItem *item = FindItemForId (itemId);
508 if (item)
509 return item->GetHelp();
510 else
511 return wxEmptyString;
512 }
513
514 void wxMenu::ProcessCommand(wxCommandEvent & event)
515 {
516 bool processed = FALSE;
517
518 // Try a callback
519 if (m_callback)
520 {
521 (void)(*(m_callback))(*this, event);
522 processed = TRUE;
523 }
524
525 // Try the menu's event handler
526 if ( !processed && GetEventHandler())
527 {
528 processed = GetEventHandler()->ProcessEvent(event);
529 }
530
531 // Try the window the menu was popped up from (and up
532 // through the hierarchy)
533 if ( !processed && GetInvokingWindow())
534 processed = GetInvokingWindow()->GetEventHandler()->ProcessEvent(event);
535 }
536
537 extern wxMenu *wxCurrentPopupMenu;
538 bool wxWindow::PopupMenu(wxMenu *menu, int x, int y)
539 {
540 menu->SetInvokingWindow(this);
541 menu->UpdateUI();
542
543 HWND hWnd = (HWND) GetHWND();
544 HMENU hMenu = (HMENU)menu->m_hMenu;
545 POINT point;
546 point.x = x;
547 point.y = y;
548 ::ClientToScreen(hWnd, &point);
549 wxCurrentPopupMenu = menu;
550 ::TrackPopupMenu(hMenu, TPM_RIGHTBUTTON, point.x, point.y, 0, hWnd, NULL);
551 wxYield();
552 wxCurrentPopupMenu = NULL;
553
554 menu->SetInvokingWindow(NULL);
555
556 return TRUE;
557 }
558
559 // Menu Bar
560 wxMenuBar::wxMenuBar()
561 {
562 m_eventHandler = this;
563
564 m_menuCount = 0;
565 m_menus = NULL;
566 m_titles = NULL;
567 m_menuBarFrame = NULL;
568 m_hMenu = 0;
569 }
570
571 wxMenuBar::wxMenuBar(int N, wxMenu *Menus[], const wxString Titles[])
572 {
573 m_eventHandler = this;
574 m_menuCount = N;
575 m_menus = Menus;
576 m_titles = new wxString[N];
577 int i;
578 for ( i = 0; i < N; i++ )
579 m_titles[i] = Titles[i];
580 m_menuBarFrame = NULL;
581 for (i = 0; i < N; i++)
582 m_menus[i]->m_menuBar = (wxMenuBar *) this;
583
584 m_hMenu = 0;
585 }
586
587 wxMenuBar::~wxMenuBar()
588 {
589 // In fact, don't want menu to be destroyed before MDI
590 // shuffling has taken place. Let it be destroyed
591 // automatically when the window is destroyed.
592
593 // DestroyMenu(menu);
594 // m_hMenu = NULL;
595
596 int i;
597 /*
598 // See remarks in ::~wxMenu() method
599 // BEWARE - this may interfere with MDI fixes, so
600 // may need to remove
601 int N = 0 ;
602
603 if (m_menuBarFrame && ((m_menuBarFrame->GetWindowStyleFlag() & wxSDI) == wxSDI))
604 {
605 if (menu)
606 N = GetMenuItemCount(menu) ;
607 for (i = N-1; i >= 0; i--)
608 RemoveMenu(menu, i, MF_BYPOSITION);
609 }
610 */
611 for (i = 0; i < m_menuCount; i++)
612 {
613 delete m_menus[i];
614 }
615 delete[] m_menus;
616 delete[] m_titles;
617
618 /* Don't destroy menu here, in case we're MDI and
619 need to do some shuffling with VALID menu handles.
620 if (menu)
621 DestroyMenu(menu);
622 m_hMenu = 0;
623 */
624 }
625
626 // Must only be used AFTER menu has been attached to frame,
627 // otherwise use individual menus to enable/disable items
628 void wxMenuBar::Enable(int Id, bool Flag)
629 {
630 int ms_flag;
631 if (Flag)
632 ms_flag = MF_ENABLED;
633 else
634 ms_flag = MF_GRAYED;
635
636 wxMenu *itemMenu = NULL;
637 wxMenuItem *item = FindItemForId(Id, &itemMenu) ;
638 if (!item)
639 return;
640
641 if (itemMenu->m_hMenu)
642 EnableMenuItem((HMENU)itemMenu->m_hMenu, Id, MF_BYCOMMAND | ms_flag);
643 else if (itemMenu->m_savehMenu)
644 EnableMenuItem((HMENU)itemMenu->m_savehMenu, Id, MF_BYCOMMAND | ms_flag);
645
646 }
647
648 void wxMenuBar::EnableTop(int pos, bool flag)
649 {
650 int ms_flag;
651 if (flag)
652 ms_flag = MF_ENABLED;
653 else
654 ms_flag = MF_GRAYED;
655
656 EnableMenuItem((HMENU)m_hMenu, pos, MF_BYPOSITION | ms_flag);
657 DrawMenuBar((HWND) m_menuBarFrame->GetHWND()) ;
658 }
659
660 // Must only be used AFTER menu has been attached to frame,
661 // otherwise use individual menus
662 void wxMenuBar::Check(int Id, bool Flag)
663 {
664 wxMenu *itemMenu = NULL;
665 wxMenuItem *item = FindItemForId(Id, &itemMenu) ;
666 if (!item)
667 return;
668
669 if (!item->IsCheckable())
670 return ;
671 int ms_flag;
672 if (Flag)
673 ms_flag = MF_CHECKED;
674 else
675 ms_flag = MF_UNCHECKED;
676
677 if (itemMenu->m_hMenu)
678 CheckMenuItem((HMENU)itemMenu->m_hMenu, Id, MF_BYCOMMAND | ms_flag);
679 else if (itemMenu->m_savehMenu)
680 CheckMenuItem((HMENU)itemMenu->m_savehMenu, Id, MF_BYCOMMAND | ms_flag);
681
682 // CheckMenuItem((HMENU)m_hMenu, Id, MF_BYCOMMAND | ms_flag);
683 }
684
685 bool wxMenuBar::Checked(int Id) const
686 {
687 wxMenu *itemMenu = NULL;
688 wxMenuItem *item = FindItemForId(Id, &itemMenu) ;
689 if (!item)
690 return FALSE;
691
692 int Flag = 0;
693
694 if (itemMenu->m_hMenu)
695 Flag=GetMenuState((HMENU)itemMenu->m_hMenu, Id, MF_BYCOMMAND) ;
696 else if (itemMenu->m_savehMenu)
697 Flag=GetMenuState((HMENU)itemMenu->m_savehMenu, Id, MF_BYCOMMAND) ;
698
699 // Flag=GetMenuState((HMENU)m_hMenu, Id, MF_BYCOMMAND) ;
700
701 if (Flag&MF_CHECKED)
702 return TRUE ;
703 else
704 return FALSE ;
705 }
706
707 bool wxMenuBar::Enabled(int Id) const
708 {
709 wxMenu *itemMenu = NULL;
710 wxMenuItem *item = FindItemForId(Id, &itemMenu) ;
711 if (!item)
712 return FALSE;
713
714 int Flag ;
715
716 if (itemMenu->m_hMenu)
717 Flag=GetMenuState((HMENU)itemMenu->m_hMenu, Id, MF_BYCOMMAND) ;
718 else if (itemMenu->m_savehMenu)
719 Flag=GetMenuState((HMENU)itemMenu->m_savehMenu, Id, MF_BYCOMMAND) ;
720
721 if (Flag&MF_ENABLED)
722 return TRUE ;
723 else
724 return FALSE ;
725 }
726
727
728 void wxMenuBar::SetLabel(int Id, const wxString& label)
729 {
730 wxMenu *itemMenu = NULL;
731 wxMenuItem *item = FindItemForId(Id, &itemMenu) ;
732
733 if (!item)
734 return;
735
736 if (itemMenu->m_hMenu)
737 {
738 UINT was_flag = GetMenuState((HMENU)itemMenu->m_hMenu,Id,MF_BYCOMMAND) ;
739 ModifyMenu((HMENU)itemMenu->m_hMenu,Id,MF_BYCOMMAND|MF_STRING|was_flag,Id,(const char *)label) ;
740 }
741 else if (itemMenu->m_savehMenu)
742 {
743 UINT was_flag = GetMenuState((HMENU)itemMenu->m_savehMenu,Id,MF_BYCOMMAND) ;
744 ModifyMenu((HMENU)itemMenu->m_savehMenu,Id,MF_BYCOMMAND|MF_STRING|was_flag,Id,(const char *)label) ;
745 }
746 }
747
748 wxString wxMenuBar::GetLabel(int Id) const
749 {
750 wxMenu *itemMenu = NULL;
751 wxMenuItem *item = FindItemForId(Id, &itemMenu) ;
752
753 if (!item)
754 return wxString("");
755
756 static char tmp[128] ;
757 int len = 0;
758 if (itemMenu->m_hMenu)
759 {
760 len = GetMenuString((HMENU)itemMenu->m_hMenu,Id,tmp,127,MF_BYCOMMAND) ;
761 }
762 else if (itemMenu->m_savehMenu)
763 {
764 len = GetMenuString((HMENU)itemMenu->m_savehMenu,Id,tmp,127,MF_BYCOMMAND) ;
765 }
766
767 // int len = GetMenuString((HMENU)m_hMenu,Id,tmp,127,MF_BYCOMMAND) ;
768 tmp[len] = '\0' ;
769 return wxString(tmp) ;
770 }
771
772 void wxMenuBar::SetLabelTop(int pos, const wxString& label)
773 {
774 UINT was_flag = GetMenuState((HMENU)m_hMenu,pos,MF_BYPOSITION) ;
775 if (was_flag&MF_POPUP)
776 {
777 was_flag &= 0xff ;
778 HMENU popup = GetSubMenu((HMENU)m_hMenu,pos) ;
779 ModifyMenu((HMENU)m_hMenu,pos,MF_BYPOSITION|MF_STRING|was_flag,(UINT)popup,(const char *)label) ;
780 }
781 else
782 ModifyMenu((HMENU)m_hMenu,pos,MF_BYPOSITION|MF_STRING|was_flag,pos,(const char *)label) ;
783 }
784
785 wxString wxMenuBar::GetLabelTop(int pos) const
786 {
787 static char tmp[128] ;
788 int len = GetMenuString((HMENU)m_hMenu,pos,tmp,127,MF_BYPOSITION) ;
789 tmp[len] = '\0' ;
790 return wxString(tmp);
791 }
792
793 bool wxMenuBar::OnDelete(wxMenu *a_menu, int pos)
794 {
795 if (!m_menuBarFrame)
796 return TRUE;
797
798 if (RemoveMenu((HMENU)m_hMenu, (UINT)pos, MF_BYPOSITION)) {
799 m_menus[pos]->m_hMenu = m_menus[pos]->m_savehMenu;
800 m_menus[pos]->m_savehMenu = 0;
801
802 if (m_menuBarFrame) {
803 DrawMenuBar((HWND) m_menuBarFrame->GetHWND()) ;
804 }
805
806 return TRUE;
807 }
808
809 return FALSE;
810 }
811
812 bool wxMenuBar::OnAppend(wxMenu *a_menu, const char *title)
813 {
814 if (!a_menu->m_hMenu)
815 return FALSE;
816
817 if (!m_menuBarFrame)
818 return TRUE;
819
820 a_menu->m_savehMenu = a_menu->m_hMenu;
821 a_menu->m_hMenu = 0;
822
823 AppendMenu((HMENU)m_hMenu, MF_POPUP | MF_STRING, (UINT)a_menu->m_savehMenu, title);
824
825 DrawMenuBar((HWND) m_menuBarFrame->GetHWND());
826
827 return TRUE;
828 }
829
830 void wxMenuBar::Append (wxMenu * menu, const wxString& title)
831 {
832 if (!OnAppend(menu, title))
833 return;
834
835 m_menuCount ++;
836 wxMenu **new_menus = new wxMenu *[m_menuCount];
837 wxString *new_titles = new wxString[m_menuCount];
838 int i;
839
840 for (i = 0; i < m_menuCount - 1; i++)
841 {
842 new_menus[i] = m_menus[i];
843 m_menus[i] = NULL;
844 new_titles[i] = m_titles[i];
845 m_titles[i] = "";
846 }
847 if (m_menus)
848 {
849 delete[]m_menus;
850 delete[]m_titles;
851 }
852 m_menus = new_menus;
853 m_titles = new_titles;
854
855 m_menus[m_menuCount - 1] = (wxMenu *)menu;
856 m_titles[m_menuCount - 1] = title;
857
858 ((wxMenu *)menu)->m_menuBar = (wxMenuBar *) this;
859 ((wxMenu *)menu)->SetParent(this);
860 }
861
862 void wxMenuBar::Delete(wxMenu * menu, int i)
863 {
864 int j;
865 int ii = (int) i;
866
867 if (menu != 0) {
868 for (ii = 0; ii < m_menuCount; ii++) {
869 if (m_menus[ii] == menu)
870 break;
871 }
872 if (ii >= m_menuCount)
873 return;
874 } else {
875 if (ii < 0 || ii >= m_menuCount)
876 return;
877 menu = m_menus[ii];
878 }
879
880 if (!OnDelete(menu, ii))
881 return;
882
883 menu->SetParent(NULL);
884
885 -- m_menuCount;
886 for (j = ii; j < m_menuCount; j++) {
887 m_menus[j] = m_menus[j + 1];
888 m_titles[j] = m_titles[j + 1];
889 }
890 }
891
892 // Find the menu menuString, item itemString, and return the item id.
893 // Returns -1 if none found.
894 int wxMenuBar::FindMenuItem (const wxString& menuString, const wxString& itemString) const
895 {
896 char buf1[200];
897 char buf2[200];
898 wxStripMenuCodes ((char *)(const char *)menuString, buf1);
899 int i;
900 for (i = 0; i < m_menuCount; i++)
901 {
902 wxStripMenuCodes ((char *)(const char *)m_titles[i], buf2);
903 if (strcmp (buf1, buf2) == 0)
904 return m_menus[i]->FindItem (itemString);
905 }
906 return -1;
907 }
908
909 wxMenuItem *wxMenuBar::FindItemForId (int Id, wxMenu ** itemMenu) const
910 {
911 if (itemMenu)
912 *itemMenu = NULL;
913
914 wxMenuItem *item = NULL;
915 int i;
916 for (i = 0; i < m_menuCount; i++)
917 {
918 item = m_menus[i]->FindItemForId (Id, itemMenu);
919 if (item)
920 return item;
921 }
922 return NULL;
923 }
924
925 void wxMenuBar::SetHelpString (int Id, const wxString& helpString)
926 {
927 int i;
928 for (i = 0; i < m_menuCount; i++)
929 {
930 if (m_menus[i]->FindItemForId (Id))
931 {
932 m_menus[i]->SetHelpString (Id, helpString);
933 return;
934 }
935 }
936 }
937
938 wxString wxMenuBar::GetHelpString (int Id) const
939 {
940 int i;
941 for (i = 0; i < m_menuCount; i++)
942 {
943 if (m_menus[i]->FindItemForId (Id))
944 return wxString(m_menus[i]->GetHelpString (Id));
945 }
946 return wxString("");
947 }
948
949 wxWindow *wxMenu::GetWindow() const
950 {
951 if ( m_pInvokingWindow != NULL )
952 return m_pInvokingWindow;
953 if ( m_menuBar != NULL)
954 return m_menuBar->m_menuBarFrame;
955 return NULL;
956 }
957
958 WXHMENU wxMenu::GetHMenu() const
959 {
960 if ( m_hMenu != 0 )
961 return m_hMenu;
962 else if ( m_savehMenu != 0 )
963 return m_savehMenu;
964
965 return 0;
966 }
967
968 // Update a menu and all submenus recursively.
969 // source is the object that has the update event handlers
970 // defined for it. If NULL, the menu or associated window
971 // will be used.
972 void wxMenu::UpdateUI(wxEvtHandler* source)
973 {
974 if (!source && GetInvokingWindow())
975 source = GetInvokingWindow()->GetEventHandler();
976 if (!source)
977 source = GetEventHandler();
978 if (!source)
979 source = this;
980
981 wxNode* node = GetItems().First();
982 while (node)
983 {
984 wxMenuItem* item = (wxMenuItem*) node->Data();
985 if ( !item->IsSeparator() )
986 {
987 wxWindowID id = item->GetId();
988 wxUpdateUIEvent event(id);
989 event.SetEventObject( source );
990
991 if (source->ProcessEvent(event))
992 {
993 if (event.GetSetText())
994 SetLabel(id, event.GetText());
995 if (event.GetSetChecked())
996 Check(id, event.GetChecked());
997 if (event.GetSetEnabled())
998 Enable(id, event.GetEnabled());
999 }
1000
1001 if (item->GetSubMenu())
1002 item->GetSubMenu()->UpdateUI(source);
1003 }
1004 node = node->Next();
1005 }
1006 }