1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxMenu, wxMenuBar, wxMenuItem
4 // Author: William Osborne
8 // Copyright: (c) William Osborne
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ===========================================================================
14 // ===========================================================================
16 // ---------------------------------------------------------------------------
18 // ---------------------------------------------------------------------------
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "menu.h"
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
42 #include "wx/ownerdrw.h"
45 // other standard headers
53 // ----------------------------------------------------------------------------
55 // ----------------------------------------------------------------------------
57 extern wxMenu
*wxCurrentPopupMenu
;
59 // ----------------------------------------------------------------------------
61 // ----------------------------------------------------------------------------
63 // the (popup) menu title has this special id
64 static const int idMenuTitle
= -3;
66 // ----------------------------------------------------------------------------
68 // ----------------------------------------------------------------------------
70 // ============================================================================
72 // ============================================================================
74 #include <wx/listimpl.cpp>
76 WX_DEFINE_LIST( wxMenuInfoList
) ;
78 #if wxUSE_EXTENDED_RTTI
80 WX_DEFINE_FLAGS( wxMenuStyle
)
82 wxBEGIN_FLAGS( wxMenuStyle
)
83 wxFLAGS_MEMBER(wxMENU_TEAROFF
)
84 wxEND_FLAGS( wxMenuStyle
)
86 IMPLEMENT_DYNAMIC_CLASS_XTI(wxMenu
, wxEvtHandler
,"wx/menu.h")
88 wxCOLLECTION_TYPE_INFO( wxMenuItem
* , wxMenuItemList
) ;
90 template<> void wxCollectionToVariantArray( wxMenuItemList
const &theList
, wxxVariantArray
&value
)
92 wxListCollectionToVariantArray
<wxMenuItemList::compatibility_iterator
>( theList
, value
) ;
95 wxBEGIN_PROPERTIES_TABLE(wxMenu
)
96 wxEVENT_PROPERTY( Select
, wxEVT_COMMAND_MENU_SELECTED
, wxCommandEvent
)
97 wxPROPERTY( Title
, wxString
, SetTitle
, GetTitle
, wxString(), 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
98 wxREADONLY_PROPERTY_FLAGS( MenuStyle
, wxMenuStyle
, long , GetStyle
, EMPTY_MACROVALUE
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
99 wxPROPERTY_COLLECTION( MenuItems
, wxMenuItemList
, wxMenuItem
* , Append
, GetMenuItems
, 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
100 wxEND_PROPERTIES_TABLE()
102 wxBEGIN_HANDLERS_TABLE(wxMenu
)
103 wxEND_HANDLERS_TABLE()
105 wxDIRECT_CONSTRUCTOR_2( wxMenu
, wxString
, Title
, long , MenuStyle
)
107 WX_DEFINE_FLAGS( wxMenuBarStyle
)
109 wxBEGIN_FLAGS( wxMenuBarStyle
)
110 wxFLAGS_MEMBER(wxMB_DOCKABLE
)
111 wxEND_FLAGS( wxMenuBarStyle
)
113 // the negative id would lead the window (its superclass !) to vetoe streaming out otherwise
114 bool wxMenuBarStreamingCallback( const wxObject
*WXUNUSED(object
), wxWriter
* , wxPersister
* , wxxVariantArray
& )
119 IMPLEMENT_DYNAMIC_CLASS_XTI_CALLBACK(wxMenuBar
, wxWindow
,"wx/menu.h",wxMenuBarStreamingCallback
)
121 IMPLEMENT_DYNAMIC_CLASS_XTI(wxMenuInfo
, wxObject
, "wx/menu.h" )
123 wxBEGIN_PROPERTIES_TABLE(wxMenuInfo
)
124 wxREADONLY_PROPERTY( Menu
, wxMenu
* , GetMenu
, EMPTY_MACROVALUE
, 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
125 wxREADONLY_PROPERTY( Title
, wxString
, GetTitle
, wxString() , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
126 wxEND_PROPERTIES_TABLE()
128 wxBEGIN_HANDLERS_TABLE(wxMenuInfo
)
129 wxEND_HANDLERS_TABLE()
131 wxCONSTRUCTOR_2( wxMenuInfo
, wxMenu
* , Menu
, wxString
, Title
)
133 wxCOLLECTION_TYPE_INFO( wxMenuInfo
* , wxMenuInfoList
) ;
135 template<> void wxCollectionToVariantArray( wxMenuInfoList
const &theList
, wxxVariantArray
&value
)
137 wxListCollectionToVariantArray
<wxMenuInfoList::compatibility_iterator
>( theList
, value
) ;
140 wxBEGIN_PROPERTIES_TABLE(wxMenuBar
)
141 wxPROPERTY_COLLECTION( MenuInfos
, wxMenuInfoList
, wxMenuInfo
* , Append
, GetMenuInfos
, 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
142 wxEND_PROPERTIES_TABLE()
144 wxBEGIN_HANDLERS_TABLE(wxMenuBar
)
145 wxEND_HANDLERS_TABLE()
147 wxCONSTRUCTOR_DUMMY( wxMenuBar
)
150 IMPLEMENT_DYNAMIC_CLASS(wxMenu
, wxEvtHandler
)
151 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar
, wxWindow
)
152 IMPLEMENT_DYNAMIC_CLASS(wxMenuInfo
, wxObject
)
155 const wxMenuInfoList
& wxMenuBar::GetMenuInfos() const
157 wxMenuInfoList
* list
= const_cast< wxMenuInfoList
* >( &m_menuInfos
) ;
158 WX_CLEAR_LIST( wxMenuInfoList
, *list
) ;
159 for( size_t i
= 0 ; i
< GetMenuCount() ; ++i
)
161 wxMenuInfo
* info
= new wxMenuInfo() ;
162 info
->Create( const_cast<wxMenuBar
*>(this)->GetMenu(i
) , GetLabelTop(i
) ) ;
163 list
->Append( info
) ;
168 // ---------------------------------------------------------------------------
169 // wxMenu construction, adding and removing menu items
170 // ---------------------------------------------------------------------------
172 // Construct a menu with optional title (then use append)
177 // The wxWindow destructor will take care of deleting the submenus.
186 void wxMenu::Attach(wxMenuBarBase
*menubar
)
188 wxMenuBase::Attach(menubar
);
193 int wxMenu::FindAccel(int id
) const
198 void wxMenu::UpdateAccel(wxMenuItem
*item
)
202 #endif // wxUSE_ACCEL
204 // append a new item or submenu to the menu
205 bool wxMenu::DoInsertOrAppend(wxMenuItem
*pItem
, size_t pos
)
207 if ( IsAttached() && GetMenuBar()->IsAttached() )
209 // Regenerate the menu resource
210 GetMenuBar()->Refresh();
216 void wxMenu::EndRadioGroup()
220 wxMenuItem
* wxMenu::DoAppend(wxMenuItem
*item
)
222 wxCHECK_MSG( item
, NULL
, _T("NULL item in wxMenu::DoAppend") );
224 if(!wxMenuBase::DoAppend(item
) || !DoInsertOrAppend(item
))
228 else if(IsAttached() && GetMenuBar()->IsAttached())
230 // Regenerate the menu resource
231 GetMenuBar()->Refresh();
237 wxMenuItem
* wxMenu::DoInsert(size_t pos
, wxMenuItem
*item
)
239 if (wxMenuBase::DoInsert(pos
, item
) && DoInsertOrAppend(item
, pos
))
245 wxMenuItem
*wxMenu::DoRemove(wxMenuItem
*item
)
247 // we need to find the items position in the child list
249 wxMenuItemList::compatibility_iterator node
= GetMenuItems().GetFirst();
250 for ( pos
= 0; node
; pos
++ )
252 if ( node
->GetData() == item
)
255 node
= node
->GetNext();
258 // DoRemove() (unlike Remove) can only be called for existing item!
259 wxCHECK_MSG( node
, NULL
, wxT("bug in wxMenu::Remove logic") );
261 // remove the item from the menu
262 wxMenuItem
*ret
=wxMenuBase::DoRemove(item
);
264 if ( IsAttached() && GetMenuBar()->IsAttached() )
266 // Regenerate the menu resource
267 GetMenuBar()->Refresh();
273 // ---------------------------------------------------------------------------
274 // accelerator helpers
275 // ---------------------------------------------------------------------------
279 // create the wxAcceleratorEntries for our accels and put them into provided
280 // array - return the number of accels we have
281 size_t wxMenu::CopyAccels(wxAcceleratorEntry
*accels
) const
283 size_t count
= GetAccelCount();
284 for ( size_t n
= 0; n
< count
; n
++ )
286 *accels
++ = *m_accels
[n
];
292 #endif // wxUSE_ACCEL
294 // ---------------------------------------------------------------------------
296 // ---------------------------------------------------------------------------
298 void wxMenu::SetTitle(const wxString
& label
)
302 if ( IsAttached() && GetMenuBar()->IsAttached() )
304 // Regenerate the menu resource
305 GetMenuBar()->Refresh();
309 // ---------------------------------------------------------------------------
311 // ---------------------------------------------------------------------------
313 bool wxMenu::PalmCommand(WXUINT
WXUNUSED(param
), WXWORD id
)
318 // ---------------------------------------------------------------------------
320 // ---------------------------------------------------------------------------
322 wxWindow
*wxMenu::GetWindow() const
327 // ---------------------------------------------------------------------------
329 // ---------------------------------------------------------------------------
331 void wxMenuBar::Init()
335 wxMenuBar::wxMenuBar()
339 wxMenuBar::wxMenuBar( long WXUNUSED(style
) )
343 wxMenuBar::wxMenuBar(int count
, wxMenu
*menus
[], const wxString titles
[])
347 wxMenuBar::~wxMenuBar()
351 // ---------------------------------------------------------------------------
353 // ---------------------------------------------------------------------------
355 void wxMenuBar::Refresh()
357 wxCHECK_RET( IsAttached(), wxT("can't refresh unattached menubar") );
359 // Regenerate the menu resource
363 WXHMENU
wxMenuBar::Create()
368 int wxMenuBar::PalmPositionForWxMenu(wxMenu
*menu
, int wxpos
)
373 // ---------------------------------------------------------------------------
374 // wxMenuBar functions to work with the top level submenus
375 // ---------------------------------------------------------------------------
377 void wxMenuBar::EnableTop(size_t pos
, bool enable
)
379 // Palm OS does not have support for grayed or disabled items
382 void wxMenuBar::SetLabelTop(size_t pos
, const wxString
& label
)
384 wxCHECK_RET( pos
< GetMenuCount(), wxT("invalid menu index") );
386 m_titles
[pos
]=wxStripMenuCodes(label
);
393 // Regenerate the menu resource
397 wxString
wxMenuBar::GetLabelTop(size_t pos
) const
399 wxCHECK_MSG( pos
< GetMenuCount(), wxEmptyString
,
400 wxT("invalid menu index in wxMenuBar::GetLabelTop") );
402 return wxMenuItem::GetLabelFromText(m_titles
[pos
]);
405 // ---------------------------------------------------------------------------
406 // wxMenuBar construction
407 // ---------------------------------------------------------------------------
409 wxMenu
*wxMenuBar::Replace(size_t pos
, wxMenu
*menu
, const wxString
& title
)
411 wxMenu
*menuOld
= wxMenuBarBase::Replace(pos
, menu
, title
);
415 m_titles
[pos
]=wxStripMenuCodes(title
);
419 // Regenerate the menu resource
426 bool wxMenuBar::Insert(size_t pos
, wxMenu
*menu
, const wxString
& title
)
428 if ( !wxMenuBarBase::Insert(pos
, menu
, title
) )
431 m_titles
.Insert(wxStripMenuCodes(title
), pos
);
435 // Regenerate the menu resource
442 bool wxMenuBar::Append(wxMenu
*menu
, const wxString
& title
)
444 if ( !wxMenuBarBase::Append(menu
, title
) )
447 m_titles
.Add(wxStripMenuCodes(title
));
451 // Regenerate the menu resource
458 wxMenu
*wxMenuBar::Remove(size_t pos
)
460 wxMenu
*menu
= wxMenuBarBase::Remove(pos
);
464 m_titles
.RemoveAt(pos
);
468 // Regenerate the menu resource
477 void wxMenuBar::RebuildAccelTable()
481 #endif // wxUSE_ACCEL
483 int wxMenuBar::ProcessCommand(int ItemID
)
488 int MenuNum
=(ItemID
/1000)-1;
489 int ItemNum
=(ItemID
-(1000*(MenuNum
+1)));
491 // Should never happen, but it doesn't hurt to check anyway.
492 if(MenuNum
>GetMenuCount())
496 wxMenu
*ActiveMenu
=GetMenu(MenuNum
);
498 // Make sure this is a valid item.
499 if(ItemNum
>ActiveMenu
->GetMenuItemCount())
503 wxMenuItem
*ActiveItem
=ActiveMenu
->FindItemByPosition(ItemNum
);
504 int ActiveID
=ActiveItem
->GetId();
509 /* Palm OS does not have good dynamic menu support. About all you can do with
510 * the standard API calls is to add new items to an existing drop-down menu and
511 * hide/show items in a drop-down menu. It is impossible to add, hide, or
512 * change the label on a drop-down menu.
514 * The easiest and simplest way around this limitation is to modify the Palm OS
515 * MenuBarType structure directly. This gives limited ability to change the
516 * label on a drop-down menu. I have not been able to find a safe way to add,
517 * delete, or resize drop-down menus in OS 6.
519 * The following routine attempt to work around these limitations present in the
520 * Palm OS API to provide limited dynamic menu support. This solution is far
521 * from perfect, but the only other option is to wait for PalmSource to add full
522 * dynamic menu support, or to recreate the Palm OS menu system from scratch.
524 * This system is limited in that no more than 4 drop-down menus are allowed per
525 * menu bar, and the label for each drop-down menu is limited to 8 characters of
526 * text. However, this menu system should work for most applications.
528 * Basically the menu routines select one of four menu bars, depending on
529 * whether or not the requested menu bar has one, two, three, or four drop-down
532 * These four "template" menu bars contain one, two, three, or four drop-down
533 * menus. Each menu has a dummy menu item attached to it to allow the Palm OS
534 * MenuAddItem function to add the real items.
536 * The labels on the drop-down menus are then replaced with the labels of the
539 * The menu is then attached to the active window and the MenuAddItem API
540 * function is called to add the items to each drop-down menu. Finally,
541 * MenuHideItem is called to remove the dummy items from each drop-down menu.
543 void wxMenuBar::LoadMenu()
548 // Handle to the currently running application database
551 // Get app database reference - needed for some Palm OS Menu API calls.
552 SysGetModuleDatabase(SysGetRefNum(), NULL
, &AppDB
);
554 // Get the number of menus
555 int NumMenus
=GetMenuCount();
557 // Set up the pointers and handles
558 char *PalmOSMenuBarPtr
;
559 MemHandle PalmOSMenuBar
;
561 // Load the menu template and set up the menu pointers
564 PalmOSMenuBar
=DmGetResource(AppDB
,'MBAR',1000);
565 PalmOSMenuBarPtr
=(char *)MemHandleLock(PalmOSMenuBar
);
567 PalmOSMenuBarPtr
+=74;
571 PalmOSMenuBar
=DmGetResource(AppDB
,'MBAR',2000);
572 PalmOSMenuBarPtr
=(char *)MemHandleLock(PalmOSMenuBar
);
574 PalmOSMenuBarPtr
+=116;
578 PalmOSMenuBar
=DmGetResource(AppDB
,'MBAR',3000);
579 PalmOSMenuBarPtr
=(char *)MemHandleLock(PalmOSMenuBar
);
581 PalmOSMenuBarPtr
+=158;
585 // We support a maximum of 4 menus, so make sure that do not create
586 // more than we can handle.
589 PalmOSMenuBar
=DmGetResource(AppDB
,'MBAR',4000);
590 PalmOSMenuBarPtr
=(char *)MemHandleLock(PalmOSMenuBar
);
592 PalmOSMenuBarPtr
+=200;
595 // Set the proper names for the drop-down triggers.
596 for(i
=0;i
<NumMenus
;i
++)
598 // Clear out the old label
599 char buffer
[8]={' ',' ',' ',' ',' ',' ',' ',' '};
600 MemMove(PalmOSMenuBarPtr
,buffer
,8);
602 wxString MenuTitle
=m_titles
.Item(i
);
604 // Make sure we don't copy more than 8 bytes for the label
605 int LengthToCopy
=MenuTitle
.length();
609 MemMove(PalmOSMenuBarPtr
,MenuTitle
,LengthToCopy
);
610 PalmOSMenuBarPtr
+=11;
613 // We are done with the menu pointer.
614 MemHandleUnlock(PalmOSMenuBar
);
615 DmReleaseResource(PalmOSMenuBar
);
617 // We must make the menu active before we can add items to the drop-down
619 FrmSetMenu(FrmGetActiveForm(),AppDB
,NumMenus
*1000);
621 /* Add the menu items to the drop-down triggers. This must be done after
622 * setting the triggers, because setting the names of drop-down triggers
623 * that have a variable number of items requires carefull calculation of
624 * the offsets in the MenuBarType structure. Setting the triggers first
627 for(i
=0;i
<NumMenus
;i
++)
629 wxMenu
*CurrentMenu
=GetMenu(i
);
631 for(j
=0;j
<CurrentMenu
->GetMenuItemCount();j
++)
633 wxMenuItem
*CurrentItem
=CurrentMenu
->FindItemByPosition(j
);
634 wxString ItemLabel
=CurrentItem
->GetLabel();
636 if(CurrentItem
->IsSeparator()==true)
638 char Separator
=MenuSeparatorChar
;
640 MenuAddItem(9000+i
,((i
*1000)+1000)+j
,0x00,&Separator
);
642 MenuAddItem(((i
*1000)+1000)+j
-1,((i
*1000)+1000)+j
,0x00,&Separator
);
647 MenuAddItem(9000+i
,((i
*1000)+1000)+j
,0x00,ItemLabel
);
649 MenuAddItem(((i
*1000)+1000)+j
-1,((i
*1000)+1000)+j
,0x00,ItemLabel
);
653 // Hide the dummy menu item, since we don't need it anymore.
654 MenuHideItem(9000+i
);
658 void wxMenuBar::Attach(wxFrame
*frame
)
660 wxMenuBarBase::Attach(frame
);
665 #if defined(__WXWINCE__) && (_WIN32_WCE >= 400 && !defined(__POCKETPC__) && !defined(__SMARTPHONE__))
666 bool wxMenuBar::AddAdornments(long style
)
672 void wxMenuBar::Detach()
674 wxMenuBarBase::Detach();
677 #endif // wxUSE_MENUS