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