]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/msw/menu.cpp
more backwards compatibility for printing
[wxWidgets.git] / src / msw / menu.cpp
... / ...
CommitLineData
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
45extern wxMenu *wxCurrentPopupMenu;
46
47// ----------------------------------------------------------------------------
48// constants
49// ----------------------------------------------------------------------------
50
51// the (popup) menu title has this special id
52static 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)
74wxMenu::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.
98wxMenu::~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
148void wxMenu::Break()
149{
150 m_doBreak = TRUE ;
151}
152
153// function appends a new item or submenu to the menu
154void 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
220void wxMenu::AppendSeparator()
221{
222 Append(new wxMenuItem(this, ID_SEPARATOR));
223}
224
225// Pullright item
226void 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
233void 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
240void 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
277void 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
285bool 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
293void 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
301bool 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
309void 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
368const wxString wxMenu::GetTitle() const
369{
370 return m_title;
371}
372
373void 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
407wxString 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
419bool 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.
437int 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
464wxMenuItem *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
492void 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
501wxString 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
513void 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
537bool 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
559wxMenuBar::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
569wxMenuBar::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
579wxMenuBar::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
595wxMenuBar::~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
636void 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
648void 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
658void 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
670bool 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
682bool 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
694void 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
707wxString 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
725void 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
743wxString 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
755bool 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
774bool 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
792void 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
824void 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.
856int 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
871wxMenuItem *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
887void 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
900wxString 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
922wxWindow *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
932WXHMENU 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.
947void 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}