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