]> git.saurik.com Git - wxWidgets.git/blob - src/palmos/menu.cpp
don't declare inline function with dllexport declaration, this provokes mingw32 warni...
[wxWidgets.git] / src / palmos / menu.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/palmos/menu.cpp
3 // Purpose: wxMenu, wxMenuBar, wxMenuItem
4 // Author: William Osborne - minimal working wxPalmOS port
5 // Modified by:
6 // Created: 10/12/04
7 // RCS-ID: $Id$
8 // Copyright: (c) William Osborne
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ===========================================================================
13 // declarations
14 // ===========================================================================
15
16 // ---------------------------------------------------------------------------
17 // headers
18 // ---------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #if wxUSE_MENUS
28
29 #include "wx/menu.h"
30
31 #ifndef WX_PRECOMP
32 #include "wx/frame.h"
33 #include "wx/utils.h"
34 #include "wx/intl.h"
35 #include "wx/log.h"
36 #endif
37
38 #if wxUSE_OWNER_DRAWN
39 #include "wx/ownerdrw.h"
40 #endif
41
42 #include <Loader.h>
43 #include <Form.h>
44 #include <Menu.h>
45
46 // ----------------------------------------------------------------------------
47 // global variables
48 // ----------------------------------------------------------------------------
49
50 extern wxMenu *wxCurrentPopupMenu;
51
52 // ----------------------------------------------------------------------------
53 // constants
54 // ----------------------------------------------------------------------------
55
56 // the (popup) menu title has this special id
57 static const int idMenuTitle = -3;
58
59 // ----------------------------------------------------------------------------
60 // private functions
61 // ----------------------------------------------------------------------------
62
63 // ============================================================================
64 // implementation
65 // ============================================================================
66
67 #include "wx/listimpl.cpp"
68
69 WX_DEFINE_LIST( wxMenuInfoList )
70
71 #if wxUSE_EXTENDED_RTTI
72
73 WX_DEFINE_FLAGS( wxMenuStyle )
74
75 wxBEGIN_FLAGS( wxMenuStyle )
76 wxFLAGS_MEMBER(wxMENU_TEAROFF)
77 wxEND_FLAGS( wxMenuStyle )
78
79 IMPLEMENT_DYNAMIC_CLASS_XTI(wxMenu, wxEvtHandler,"wx/menu.h")
80
81 wxCOLLECTION_TYPE_INFO( wxMenuItem * , wxMenuItemList ) ;
82
83 template<> void wxCollectionToVariantArray( wxMenuItemList const &theList, wxxVariantArray &value)
84 {
85 wxListCollectionToVariantArray<wxMenuItemList::compatibility_iterator>( theList , value ) ;
86 }
87
88 wxBEGIN_PROPERTIES_TABLE(wxMenu)
89 wxEVENT_PROPERTY( Select , wxEVT_COMMAND_MENU_SELECTED , wxCommandEvent)
90 wxPROPERTY( Title, wxString , SetTitle, GetTitle, wxString(), 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
91 wxREADONLY_PROPERTY_FLAGS( MenuStyle , wxMenuStyle , long , GetStyle , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
92 wxPROPERTY_COLLECTION( MenuItems , wxMenuItemList , wxMenuItem* , Append , GetMenuItems , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
93 wxEND_PROPERTIES_TABLE()
94
95 wxBEGIN_HANDLERS_TABLE(wxMenu)
96 wxEND_HANDLERS_TABLE()
97
98 wxDIRECT_CONSTRUCTOR_2( wxMenu , wxString , Title , long , MenuStyle )
99
100 WX_DEFINE_FLAGS( wxMenuBarStyle )
101
102 wxBEGIN_FLAGS( wxMenuBarStyle )
103 wxFLAGS_MEMBER(wxMB_DOCKABLE)
104 wxEND_FLAGS( wxMenuBarStyle )
105
106 // the negative id would lead the window (its superclass !) to vetoe streaming out otherwise
107 bool wxMenuBarStreamingCallback( const wxObject *WXUNUSED(object), wxWriter * , wxPersister * , wxxVariantArray & )
108 {
109 return true ;
110 }
111
112 IMPLEMENT_DYNAMIC_CLASS_XTI_CALLBACK(wxMenuBar, wxWindow ,"wx/menu.h",wxMenuBarStreamingCallback)
113
114 IMPLEMENT_DYNAMIC_CLASS_XTI(wxMenuInfo, wxObject , "wx/menu.h" )
115
116 wxBEGIN_PROPERTIES_TABLE(wxMenuInfo)
117 wxREADONLY_PROPERTY( Menu , wxMenu* , GetMenu , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
118 wxREADONLY_PROPERTY( Title , wxString , GetTitle , wxString() , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
119 wxEND_PROPERTIES_TABLE()
120
121 wxBEGIN_HANDLERS_TABLE(wxMenuInfo)
122 wxEND_HANDLERS_TABLE()
123
124 wxCONSTRUCTOR_2( wxMenuInfo , wxMenu* , Menu , wxString , Title )
125
126 wxCOLLECTION_TYPE_INFO( wxMenuInfo * , wxMenuInfoList ) ;
127
128 template<> void wxCollectionToVariantArray( wxMenuInfoList const &theList, wxxVariantArray &value)
129 {
130 wxListCollectionToVariantArray<wxMenuInfoList::compatibility_iterator>( theList , value ) ;
131 }
132
133 wxBEGIN_PROPERTIES_TABLE(wxMenuBar)
134 wxPROPERTY_COLLECTION( MenuInfos , wxMenuInfoList , wxMenuInfo* , Append , GetMenuInfos , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
135 wxEND_PROPERTIES_TABLE()
136
137 wxBEGIN_HANDLERS_TABLE(wxMenuBar)
138 wxEND_HANDLERS_TABLE()
139
140 wxCONSTRUCTOR_DUMMY( wxMenuBar )
141
142 #else
143 IMPLEMENT_DYNAMIC_CLASS(wxMenu, wxEvtHandler)
144 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxWindow)
145 IMPLEMENT_DYNAMIC_CLASS(wxMenuInfo, wxObject)
146 #endif
147
148 const wxMenuInfoList& wxMenuBar::GetMenuInfos() const
149 {
150 wxMenuInfoList* list = const_cast< wxMenuInfoList* >( &m_menuInfos ) ;
151 WX_CLEAR_LIST( wxMenuInfoList , *list ) ;
152 for( size_t i = 0 ; i < GetMenuCount() ; ++i )
153 {
154 wxMenuInfo* info = new wxMenuInfo() ;
155 info->Create( const_cast<wxMenuBar*>(this)->GetMenu(i) , GetLabelTop(i) ) ;
156 list->Append( info ) ;
157 }
158 return m_menuInfos ;
159 }
160
161 // ---------------------------------------------------------------------------
162 // wxMenu construction, adding and removing menu items
163 // ---------------------------------------------------------------------------
164
165 // Construct a menu with optional title (then use append)
166 void wxMenu::Init()
167 {
168 }
169
170 // The wxWindow destructor will take care of deleting the submenus.
171 wxMenu::~wxMenu()
172 {
173 }
174
175 void wxMenu::Break()
176 {
177 }
178
179 void wxMenu::Attach(wxMenuBarBase *menubar)
180 {
181 wxMenuBase::Attach(menubar);
182 }
183
184 #if wxUSE_ACCEL
185
186 int wxMenu::FindAccel(int id) const
187 {
188 return wxNOT_FOUND;
189 }
190
191 void wxMenu::UpdateAccel(wxMenuItem *item)
192 {
193 }
194
195 #endif // wxUSE_ACCEL
196
197 // append a new item or submenu to the menu
198 bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos)
199 {
200 if ( IsAttached() && GetMenuBar()->IsAttached() )
201 {
202 // Regenerate the menu resource
203 GetMenuBar()->Refresh();
204 }
205
206 return true;
207 }
208
209 void wxMenu::EndRadioGroup()
210 {
211 }
212
213 wxMenuItem* wxMenu::DoAppend(wxMenuItem *item)
214 {
215 wxCHECK_MSG( item, NULL, _T("NULL item in wxMenu::DoAppend") );
216
217 if(!wxMenuBase::DoAppend(item) || !DoInsertOrAppend(item))
218 {
219 return NULL;
220 }
221 else if(IsAttached() && GetMenuBar()->IsAttached())
222 {
223 // Regenerate the menu resource
224 GetMenuBar()->Refresh();
225 }
226
227 return item;
228 }
229
230 wxMenuItem* wxMenu::DoInsert(size_t pos, wxMenuItem *item)
231 {
232 if (wxMenuBase::DoInsert(pos, item) && DoInsertOrAppend(item, pos))
233 return item;
234 else
235 return NULL;
236 }
237
238 wxMenuItem *wxMenu::DoRemove(wxMenuItem *item)
239 {
240 // we need to find the items position in the child list
241 size_t pos;
242 wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst();
243 for ( pos = 0; node; pos++ )
244 {
245 if ( node->GetData() == item )
246 break;
247
248 node = node->GetNext();
249 }
250
251 // DoRemove() (unlike Remove) can only be called for existing item!
252 wxCHECK_MSG( node, NULL, wxT("bug in wxMenu::Remove logic") );
253
254 // remove the item from the menu
255 wxMenuItem *ret=wxMenuBase::DoRemove(item);
256
257 if ( IsAttached() && GetMenuBar()->IsAttached() )
258 {
259 // Regenerate the menu resource
260 GetMenuBar()->Refresh();
261 }
262
263 return ret;
264 }
265
266 // ---------------------------------------------------------------------------
267 // accelerator helpers
268 // ---------------------------------------------------------------------------
269
270 #if wxUSE_ACCEL
271
272 // create the wxAcceleratorEntries for our accels and put them into provided
273 // array - return the number of accels we have
274 size_t wxMenu::CopyAccels(wxAcceleratorEntry *accels) const
275 {
276 size_t count = GetAccelCount();
277 for ( size_t n = 0; n < count; n++ )
278 {
279 *accels++ = *m_accels[n];
280 }
281
282 return count;
283 }
284
285 #endif // wxUSE_ACCEL
286
287 // ---------------------------------------------------------------------------
288 // set wxMenu title
289 // ---------------------------------------------------------------------------
290
291 void wxMenu::SetTitle(const wxString& label)
292 {
293 m_title = label;
294
295 if ( IsAttached() && GetMenuBar()->IsAttached() )
296 {
297 // Regenerate the menu resource
298 GetMenuBar()->Refresh();
299 }
300 }
301
302 // ---------------------------------------------------------------------------
303 // event processing
304 // ---------------------------------------------------------------------------
305
306 bool wxMenu::PalmCommand(WXUINT WXUNUSED(param), WXWORD id)
307 {
308 return false;
309 }
310
311 // ---------------------------------------------------------------------------
312 // other
313 // ---------------------------------------------------------------------------
314
315 wxWindow *wxMenu::GetWindow() const
316 {
317 return NULL;
318 }
319
320 // ---------------------------------------------------------------------------
321 // Menu Bar
322 // ---------------------------------------------------------------------------
323
324 void wxMenuBar::Init()
325 {
326 }
327
328 wxMenuBar::wxMenuBar()
329 {
330 }
331
332 wxMenuBar::wxMenuBar( long WXUNUSED(style) )
333 {
334 }
335
336 wxMenuBar::wxMenuBar(size_t count, wxMenu *menus[], const wxString titles[], long WXUNUSED(style))
337 {
338 }
339
340 wxMenuBar::~wxMenuBar()
341 {
342 }
343
344 // ---------------------------------------------------------------------------
345 // wxMenuBar helpers
346 // ---------------------------------------------------------------------------
347
348 void wxMenuBar::Refresh()
349 {
350 wxCHECK_RET( IsAttached(), wxT("can't refresh unattached menubar") );
351
352 // Regenerate the menu resource
353 LoadMenu();
354 }
355
356 WXHMENU wxMenuBar::Create()
357 {
358 return NULL;
359 }
360
361 int wxMenuBar::PalmPositionForWxMenu(wxMenu *menu, int wxpos)
362 {
363 return -1;
364 }
365
366 // ---------------------------------------------------------------------------
367 // wxMenuBar functions to work with the top level submenus
368 // ---------------------------------------------------------------------------
369
370 void wxMenuBar::EnableTop(size_t pos, bool enable)
371 {
372 // Palm OS does not have support for grayed or disabled items
373 }
374
375 void wxMenuBar::SetLabelTop(size_t pos, const wxString& label)
376 {
377 wxCHECK_RET( pos < GetMenuCount(), wxT("invalid menu index") );
378
379 m_titles[pos]=wxStripMenuCodes(label);
380
381 if ( !IsAttached() )
382 {
383 return;
384 }
385
386 // Regenerate the menu resource
387 Refresh();
388 }
389
390 wxString wxMenuBar::GetLabelTop(size_t pos) const
391 {
392 wxCHECK_MSG( pos < GetMenuCount(), wxEmptyString,
393 wxT("invalid menu index in wxMenuBar::GetLabelTop") );
394
395 return wxMenuItem::GetLabelFromText(m_titles[pos]);
396 }
397
398 // ---------------------------------------------------------------------------
399 // wxMenuBar construction
400 // ---------------------------------------------------------------------------
401
402 wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title)
403 {
404 wxMenu *menuOld = wxMenuBarBase::Replace(pos, menu, title);
405 if ( !menuOld )
406 return NULL;
407
408 m_titles[pos]=wxStripMenuCodes(title);
409
410 if ( IsAttached() )
411 {
412 // Regenerate the menu resource
413 Refresh();
414 }
415
416 return menuOld;
417 }
418
419 bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title)
420 {
421 if ( !wxMenuBarBase::Insert(pos, menu, title) )
422 return false;
423
424 m_titles.Insert(wxStripMenuCodes(title), pos);
425
426 if ( IsAttached() )
427 {
428 // Regenerate the menu resource
429 Refresh();
430 }
431
432 return true;
433 }
434
435 bool wxMenuBar::Append(wxMenu *menu, const wxString& title)
436 {
437 if ( !wxMenuBarBase::Append(menu, title) )
438 return false;
439
440 m_titles.Add(wxStripMenuCodes(title));
441
442 if(IsAttached())
443 {
444 // Regenerate the menu resource
445 Refresh();
446 }
447
448 return true;
449 }
450
451 wxMenu *wxMenuBar::Remove(size_t pos)
452 {
453 wxMenu *menu = wxMenuBarBase::Remove(pos);
454 if ( !menu )
455 return NULL;
456
457 m_titles.RemoveAt(pos);
458
459 if (IsAttached())
460 {
461 // Regenerate the menu resource
462 Refresh();
463 }
464
465 return menu;
466 }
467
468 #if wxUSE_ACCEL
469
470 void wxMenuBar::RebuildAccelTable()
471 {
472 }
473
474 #endif // wxUSE_ACCEL
475
476 int wxMenuBar::ProcessCommand(int ItemID)
477 {
478 if(!IsAttached())
479 return -1;
480
481 int MenuNum=(ItemID/1000)-1;
482 int ItemNum=(ItemID-(1000*(MenuNum+1)));
483
484 // Should never happen, but it doesn't hurt to check anyway.
485 if(MenuNum>GetMenuCount())
486 return -1;
487
488 // Get the menu
489 wxMenu *ActiveMenu=GetMenu(MenuNum);
490
491 // Make sure this is a valid item.
492 if(ItemNum>ActiveMenu->GetMenuItemCount())
493 return -1;
494
495 // Get the item
496 wxMenuItem *ActiveItem=ActiveMenu->FindItemByPosition(ItemNum);
497 int ActiveID=ActiveItem->GetId();
498
499 return ActiveID;
500 }
501
502 /* Palm OS does not have good dynamic menu support. About all you can do with
503 * the standard API calls is to add new items to an existing drop-down menu and
504 * hide/show items in a drop-down menu. It is impossible to add, hide, or
505 * change the label on a drop-down menu.
506 *
507 * The easiest and simplest way around this limitation is to modify the Palm OS
508 * MenuBarType structure directly. This gives limited ability to change the
509 * label on a drop-down menu. I have not been able to find a safe way to add,
510 * delete, or resize drop-down menus in OS 6.
511 *
512 * The following routine attempt to work around these limitations present in the
513 * Palm OS API to provide limited dynamic menu support. This solution is far
514 * from perfect, but the only other option is to wait for PalmSource to add full
515 * dynamic menu support, or to recreate the Palm OS menu system from scratch.
516 *
517 * This system is limited in that no more than 4 drop-down menus are allowed per
518 * menu bar, and the label for each drop-down menu is limited to 8 characters of
519 * text. However, this menu system should work for most applications.
520 *
521 * Basically the menu routines select one of four menu bars, depending on
522 * whether or not the requested menu bar has one, two, three, or four drop-down
523 * menus.
524 *
525 * These four "template" menu bars contain one, two, three, or four drop-down
526 * menus. Each menu has a dummy menu item attached to it to allow the Palm OS
527 * MenuAddItem function to add the real items.
528 *
529 * The labels on the drop-down menus are then replaced with the labels of the
530 * real menus.
531 *
532 * The menu is then attached to the active window and the MenuAddItem API
533 * function is called to add the items to each drop-down menu. Finally,
534 * MenuHideItem is called to remove the dummy items from each drop-down menu.
535 */
536 void wxMenuBar::LoadMenu()
537 {
538 int i=0;
539 int j=0;
540
541 // Handle to the currently running application database
542 DmOpenRef AppDB;
543
544 // Get app database reference - needed for some Palm OS Menu API calls.
545 SysGetModuleDatabase(SysGetRefNum(), NULL, &AppDB);
546
547 // Get the number of menus
548 int NumMenus=GetMenuCount();
549
550 // Set up the pointers and handles
551 char *PalmOSMenuBarPtr;
552 MemHandle PalmOSMenuBar;
553
554 // Load the menu template and set up the menu pointers
555 if(NumMenus==1)
556 {
557 PalmOSMenuBar=DmGetResource(AppDB,'MBAR',1000);
558 PalmOSMenuBarPtr=(char *)MemHandleLock(PalmOSMenuBar);
559
560 PalmOSMenuBarPtr+=74;
561 }
562 else if(NumMenus==2)
563 {
564 PalmOSMenuBar=DmGetResource(AppDB,'MBAR',2000);
565 PalmOSMenuBarPtr=(char *)MemHandleLock(PalmOSMenuBar);
566
567 PalmOSMenuBarPtr+=116;
568 }
569 else if(NumMenus==3)
570 {
571 PalmOSMenuBar=DmGetResource(AppDB,'MBAR',3000);
572 PalmOSMenuBarPtr=(char *)MemHandleLock(PalmOSMenuBar);
573
574 PalmOSMenuBarPtr+=158;
575 }
576 else
577 {
578 // We support a maximum of 4 menus, so make sure that do not create
579 // more than we can handle.
580 NumMenus=4;
581
582 PalmOSMenuBar=DmGetResource(AppDB,'MBAR',4000);
583 PalmOSMenuBarPtr=(char *)MemHandleLock(PalmOSMenuBar);
584
585 PalmOSMenuBarPtr+=200;
586 }
587
588 // Set the proper names for the drop-down triggers.
589 for(i=0;i<NumMenus;i++)
590 {
591 // Clear out the old label
592 char buffer[8]={' ',' ',' ',' ',' ',' ',' ',' '};
593 MemMove(PalmOSMenuBarPtr,buffer,8);
594
595 wxString MenuTitle=m_titles.Item(i);
596
597 // Make sure we don't copy more than 8 bytes for the label
598 int LengthToCopy=MenuTitle.length();
599 if(LengthToCopy>8)
600 LengthToCopy=8;
601
602 MemMove(PalmOSMenuBarPtr,MenuTitle,LengthToCopy);
603 PalmOSMenuBarPtr+=11;
604 }
605
606 // We are done with the menu pointer.
607 MemHandleUnlock(PalmOSMenuBar);
608 DmReleaseResource(PalmOSMenuBar);
609
610 // We must make the menu active before we can add items to the drop-down
611 // triggers.
612 FrmSetMenu(FrmGetActiveForm(),AppDB,NumMenus*1000);
613
614 /* Add the menu items to the drop-down triggers. This must be done after
615 * setting the triggers, because setting the names of drop-down triggers
616 * that have a variable number of items requires carefull calculation of
617 * the offsets in the MenuBarType structure. Setting the triggers first
618 * avoids this.
619 */
620 for(i=0;i<NumMenus;i++)
621 {
622 wxMenu *CurrentMenu=GetMenu(i);
623
624 for(j=0;j<CurrentMenu->GetMenuItemCount();j++)
625 {
626 wxMenuItem *CurrentItem=CurrentMenu->FindItemByPosition(j);
627 wxString ItemLabel=CurrentItem->GetLabel();
628
629 if(CurrentItem->IsSeparator()==true)
630 {
631 char Separator=MenuSeparatorChar;
632 if(j==0)
633 MenuAddItem(9000+i,((i*1000)+1000)+j,0x00,&Separator);
634 else
635 MenuAddItem(((i*1000)+1000)+j-1,((i*1000)+1000)+j,0x00,&Separator);
636 }
637 else
638 {
639 if(j==0)
640 MenuAddItem(9000+i,((i*1000)+1000)+j,0x00,ItemLabel);
641 else
642 MenuAddItem(((i*1000)+1000)+j-1,((i*1000)+1000)+j,0x00,ItemLabel);
643 }
644 }
645
646 // Hide the dummy menu item, since we don't need it anymore.
647 MenuHideItem(9000+i);
648 }
649 }
650
651 void wxMenuBar::Attach(wxFrame *frame)
652 {
653 // before attaching preprocess menus to not include wxID_EXIT item
654 // as PalmOS guidelines suggest
655
656 wxMenuItem *item;
657 wxMenu *menu;
658 int i;
659
660 while( item = FindItem(wxID_EXIT) )
661 {
662 menu = item->GetMenu();
663 if( !menu ) break; // something broken ?
664
665 size_t count = menu->GetMenuItemCount();
666 if( count == 0 ) break; // something broken ?
667
668 // if EXIT is last item in menu
669 if( menu->FindItemByPosition( count - 1 ) == item )
670 {
671 menu->Destroy( item );
672
673 // was more than one item?
674 // was previous separator ?
675 if( count > 2 )
676 {
677 item = menu->FindItemByPosition( count - 2 );
678 if(item && item->IsSeparator())
679 menu->Destroy( item );
680 }
681 }
682
683 // if EXIT is first item in menu
684 else if( menu->FindItemByPosition( 0 ) == item )
685 {
686 menu->Destroy( item );
687
688 // was more than one item?
689 // was previous separator ?
690 if( count > 2 )
691 {
692 item = menu->FindItemByPosition( 0 );
693 if(item && item->IsSeparator())
694 menu->Destroy( item );
695 }
696 }
697
698 // if EXIT is in the middle but before and after are selectors
699 else
700 {
701 i = 1; // 0 case already done
702 while ( (i < count) && (menu->FindItemByPosition( 0 ) != item) )
703 {
704 i++;
705 }
706
707 if (i >= count) break;
708 if (menu->FindItemByPosition( i ) != item) break;
709 menu->Destroy( item );
710 item = menu->FindItemByPosition( i );
711 if ( item &&
712 item->IsSeparator() &&
713 menu->FindItemByPosition( i-1 )->IsSeparator() )
714 {
715 // noe need for two neighbouring separators
716 menu->Destroy( item );
717 }
718 }
719 }
720
721 // check if we received any empty menu!
722 i = 0;
723 while(i < GetMenuCount())
724 {
725 menu = GetMenu(i);
726
727 if( menu && (menu->GetMenuItemCount()==0) )
728 {
729 menu = Remove( i );
730 delete menu;
731 }
732 else
733 i++;
734 }
735
736 wxMenuBarBase::Attach(frame);
737
738 LoadMenu();
739 }
740
741 void wxMenuBar::Detach()
742 {
743 wxMenuBarBase::Detach();
744 }
745
746 #endif // wxUSE_MENUS