1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/palmos/menu.cpp
3 // Purpose: wxMenu, wxMenuBar, wxMenuItem
4 // Author: William Osborne - minimal working wxPalmOS port
8 // Copyright: (c) William Osborne
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ===========================================================================
14 // ===========================================================================
16 // ---------------------------------------------------------------------------
18 // ---------------------------------------------------------------------------
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
39 #include "wx/ownerdrw.h"
44 #else // __WXPALMOS5__
45 #include <UIResources.h> // MenuRscType
51 // ----------------------------------------------------------------------------
53 // ----------------------------------------------------------------------------
55 extern wxMenu
*wxCurrentPopupMenu
;
57 // ----------------------------------------------------------------------------
59 // ----------------------------------------------------------------------------
61 // the (popup) menu title has this special id
62 static const int idMenuTitle
= -3;
64 // ----------------------------------------------------------------------------
66 // ----------------------------------------------------------------------------
68 // ============================================================================
70 // ============================================================================
72 #include "wx/listimpl.cpp"
74 WX_DEFINE_LIST( wxMenuInfoList
)
76 #if wxUSE_EXTENDED_RTTI
78 WX_DEFINE_FLAGS( wxMenuStyle
)
80 wxBEGIN_FLAGS( wxMenuStyle
)
81 wxFLAGS_MEMBER(wxMENU_TEAROFF
)
82 wxEND_FLAGS( wxMenuStyle
)
84 IMPLEMENT_DYNAMIC_CLASS_XTI(wxMenu
, wxEvtHandler
,"wx/menu.h")
86 wxCOLLECTION_TYPE_INFO( wxMenuItem
* , wxMenuItemList
) ;
88 template<> void wxCollectionToVariantArray( wxMenuItemList
const &theList
, wxxVariantArray
&value
)
90 wxListCollectionToVariantArray
<wxMenuItemList::compatibility_iterator
>( theList
, value
) ;
93 wxBEGIN_PROPERTIES_TABLE(wxMenu
)
94 wxEVENT_PROPERTY( Select
, wxEVT_COMMAND_MENU_SELECTED
, wxCommandEvent
)
95 wxPROPERTY( Title
, wxString
, SetTitle
, GetTitle
, wxString(), 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
96 wxREADONLY_PROPERTY_FLAGS( MenuStyle
, wxMenuStyle
, long , GetStyle
, EMPTY_MACROVALUE
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
97 wxPROPERTY_COLLECTION( MenuItems
, wxMenuItemList
, wxMenuItem
* , Append
, GetMenuItems
, 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
98 wxEND_PROPERTIES_TABLE()
100 wxBEGIN_HANDLERS_TABLE(wxMenu
)
101 wxEND_HANDLERS_TABLE()
103 wxDIRECT_CONSTRUCTOR_2( wxMenu
, wxString
, Title
, long , MenuStyle
)
105 WX_DEFINE_FLAGS( wxMenuBarStyle
)
107 wxBEGIN_FLAGS( wxMenuBarStyle
)
108 wxFLAGS_MEMBER(wxMB_DOCKABLE
)
109 wxEND_FLAGS( wxMenuBarStyle
)
111 // the negative id would lead the window (its superclass !) to vetoe streaming out otherwise
112 bool wxMenuBarStreamingCallback( const wxObject
*WXUNUSED(object
), wxWriter
* , wxPersister
* , wxxVariantArray
& )
117 IMPLEMENT_DYNAMIC_CLASS_XTI_CALLBACK(wxMenuBar
, wxWindow
,"wx/menu.h",wxMenuBarStreamingCallback
)
119 IMPLEMENT_DYNAMIC_CLASS_XTI(wxMenuInfo
, wxObject
, "wx/menu.h" )
121 wxBEGIN_PROPERTIES_TABLE(wxMenuInfo
)
122 wxREADONLY_PROPERTY( Menu
, wxMenu
* , GetMenu
, EMPTY_MACROVALUE
, 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
123 wxREADONLY_PROPERTY( Title
, wxString
, GetTitle
, wxString() , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
124 wxEND_PROPERTIES_TABLE()
126 wxBEGIN_HANDLERS_TABLE(wxMenuInfo
)
127 wxEND_HANDLERS_TABLE()
129 wxCONSTRUCTOR_2( wxMenuInfo
, wxMenu
* , Menu
, wxString
, Title
)
131 wxCOLLECTION_TYPE_INFO( wxMenuInfo
* , wxMenuInfoList
) ;
133 template<> void wxCollectionToVariantArray( wxMenuInfoList
const &theList
, wxxVariantArray
&value
)
135 wxListCollectionToVariantArray
<wxMenuInfoList::compatibility_iterator
>( theList
, value
) ;
138 wxBEGIN_PROPERTIES_TABLE(wxMenuBar
)
139 wxPROPERTY_COLLECTION( MenuInfos
, wxMenuInfoList
, wxMenuInfo
* , Append
, GetMenuInfos
, 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
140 wxEND_PROPERTIES_TABLE()
142 wxBEGIN_HANDLERS_TABLE(wxMenuBar
)
143 wxEND_HANDLERS_TABLE()
145 wxCONSTRUCTOR_DUMMY( wxMenuBar
)
148 IMPLEMENT_DYNAMIC_CLASS(wxMenu
, wxEvtHandler
)
149 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar
, wxWindow
)
150 IMPLEMENT_DYNAMIC_CLASS(wxMenuInfo
, wxObject
)
153 const wxMenuInfoList
& wxMenuBar::GetMenuInfos() const
155 wxMenuInfoList
* list
= const_cast< wxMenuInfoList
* >( &m_menuInfos
) ;
156 WX_CLEAR_LIST( wxMenuInfoList
, *list
) ;
157 for( size_t i
= 0 ; i
< GetMenuCount() ; ++i
)
159 wxMenuInfo
* info
= new wxMenuInfo() ;
160 info
->Create( const_cast<wxMenuBar
*>(this)->GetMenu(i
) , GetMenuLabel(i
) ) ;
161 list
->Append( info
) ;
166 // ---------------------------------------------------------------------------
167 // wxMenu construction, adding and removing menu items
168 // ---------------------------------------------------------------------------
170 // Construct a menu with optional title (then use append)
175 // The wxWindow destructor will take care of deleting the submenus.
184 void wxMenu::Attach(wxMenuBarBase
*menubar
)
186 wxMenuBase::Attach(menubar
);
191 int wxMenu::FindAccel(int id
) const
196 void wxMenu::UpdateAccel(wxMenuItem
*item
)
200 #endif // wxUSE_ACCEL
202 // append a new item or submenu to the menu
203 bool wxMenu::DoInsertOrAppend(wxMenuItem
*pItem
, size_t pos
)
205 if ( IsAttached() && GetMenuBar()->IsAttached() )
207 // Regenerate the menu resource
208 GetMenuBar()->Refresh();
214 void wxMenu::EndRadioGroup()
218 wxMenuItem
* wxMenu::DoAppend(wxMenuItem
*item
)
220 wxCHECK_MSG( item
, NULL
, wxT("NULL item in wxMenu::DoAppend") );
222 if(!wxMenuBase::DoAppend(item
) || !DoInsertOrAppend(item
))
226 else if(IsAttached() && GetMenuBar()->IsAttached())
228 // Regenerate the menu resource
229 GetMenuBar()->Refresh();
235 wxMenuItem
* wxMenu::DoInsert(size_t pos
, wxMenuItem
*item
)
237 if (wxMenuBase::DoInsert(pos
, item
) && DoInsertOrAppend(item
, pos
))
243 wxMenuItem
*wxMenu::DoRemove(wxMenuItem
*item
)
245 // we need to find the items position in the child list
247 wxMenuItemList::compatibility_iterator node
= GetMenuItems().GetFirst();
248 for ( pos
= 0; node
; pos
++ )
250 if ( node
->GetData() == item
)
253 node
= node
->GetNext();
256 // DoRemove() (unlike Remove) can only be called for existing item!
257 wxCHECK_MSG( node
, NULL
, wxT("bug in wxMenu::Remove logic") );
259 // remove the item from the menu
260 wxMenuItem
*ret
=wxMenuBase::DoRemove(item
);
262 if ( IsAttached() && GetMenuBar()->IsAttached() )
264 // Regenerate the menu resource
265 GetMenuBar()->Refresh();
271 // ---------------------------------------------------------------------------
272 // accelerator helpers
273 // ---------------------------------------------------------------------------
277 // create the wxAcceleratorEntries for our accels and put them into provided
278 // array - return the number of accels we have
279 size_t wxMenu::CopyAccels(wxAcceleratorEntry
*accels
) const
281 size_t count
= GetAccelCount();
282 for ( size_t n
= 0; n
< count
; n
++ )
284 *accels
++ = *m_accels
[n
];
290 #endif // wxUSE_ACCEL
292 // ---------------------------------------------------------------------------
294 // ---------------------------------------------------------------------------
296 void wxMenu::SetTitle(const wxString
& label
)
300 if ( IsAttached() && GetMenuBar()->IsAttached() )
302 // Regenerate the menu resource
303 GetMenuBar()->Refresh();
307 // ---------------------------------------------------------------------------
309 // ---------------------------------------------------------------------------
311 bool wxMenu::PalmCommand(WXUINT
WXUNUSED(param
), WXWORD id
)
316 // ---------------------------------------------------------------------------
318 // ---------------------------------------------------------------------------
320 wxWindow
*wxMenu::GetWindow() const
325 // ---------------------------------------------------------------------------
327 // ---------------------------------------------------------------------------
329 void wxMenuBar::Init()
333 wxMenuBar::wxMenuBar()
337 wxMenuBar::wxMenuBar( long WXUNUSED(style
) )
341 wxMenuBar::wxMenuBar(size_t count
, wxMenu
*menus
[], const wxString titles
[], long WXUNUSED(style
))
345 wxMenuBar::~wxMenuBar()
349 // ---------------------------------------------------------------------------
351 // ---------------------------------------------------------------------------
353 void wxMenuBar::Refresh()
355 wxCHECK_RET( IsAttached(), wxT("can't refresh unattached menubar") );
357 // Regenerate the menu resource
361 WXHMENU
wxMenuBar::Create()
366 int wxMenuBar::PalmPositionForWxMenu(wxMenu
*menu
, int wxpos
)
371 // ---------------------------------------------------------------------------
372 // wxMenuBar functions to work with the top level submenus
373 // ---------------------------------------------------------------------------
375 void wxMenuBar::EnableTop(size_t pos
, bool enable
)
377 // Palm OS does not have support for grayed or disabled items
380 void wxMenuBar::SetMenuLabel(size_t pos
, const wxString
& label
)
382 wxCHECK_RET( pos
< GetMenuCount(), wxT("invalid menu index") );
384 m_titles
[pos
] = label
;
391 // Regenerate the menu resource
395 wxString
wxMenuBar::GetMenuLabel(size_t pos
) const
397 wxCHECK_MSG( pos
< GetMenuCount(), wxEmptyString
,
398 wxT("invalid menu index in wxMenuBar::GetMenuLabel") );
400 return m_titles
[pos
];
403 // ---------------------------------------------------------------------------
404 // wxMenuBar construction
405 // ---------------------------------------------------------------------------
407 wxMenu
*wxMenuBar::Replace(size_t pos
, wxMenu
*menu
, const wxString
& title
)
409 wxMenu
*menuOld
= wxMenuBarBase::Replace(pos
, menu
, title
);
413 m_titles
[pos
] = title
;
417 // Regenerate the menu resource
424 bool wxMenuBar::Insert(size_t pos
, wxMenu
*menu
, const wxString
& title
)
426 if ( !wxMenuBarBase::Insert(pos
, menu
, title
) )
429 m_titles
.Insert(title
, pos
);
433 // Regenerate the menu resource
440 bool wxMenuBar::Append(wxMenu
*menu
, const wxString
& title
)
442 if ( !wxMenuBarBase::Append(menu
, title
) )
449 // Regenerate the menu resource
456 wxMenu
*wxMenuBar::Remove(size_t pos
)
458 wxMenu
*menu
= wxMenuBarBase::Remove(pos
);
462 m_titles
.RemoveAt(pos
);
466 // Regenerate the menu resource
475 void wxMenuBar::RebuildAccelTable()
479 #endif // wxUSE_ACCEL
481 int wxMenuBar::ProcessCommand(int ItemID
)
486 int MenuNum
=(ItemID
/1000)-1;
487 int ItemNum
=(ItemID
-(1000*(MenuNum
+1)));
489 // Should never happen, but it doesn't hurt to check anyway.
490 if(MenuNum
>GetMenuCount())
494 wxMenu
*ActiveMenu
=GetMenu(MenuNum
);
496 // Make sure this is a valid item.
497 if(ItemNum
>ActiveMenu
->GetMenuItemCount())
501 wxMenuItem
*ActiveItem
=ActiveMenu
->FindItemByPosition(ItemNum
);
502 int ActiveID
=ActiveItem
->GetId();
507 /* Palm OS does not have good dynamic menu support. About all you can do with
508 * the standard API calls is to add new items to an existing drop-down menu and
509 * hide/show items in a drop-down menu. It is impossible to add, hide, or
510 * change the label on a drop-down menu.
512 * The easiest and simplest way around this limitation is to modify the Palm OS
513 * MenuBarType structure directly. This gives limited ability to change the
514 * label on a drop-down menu. I have not been able to find a safe way to add,
515 * delete, or resize drop-down menus in OS 6.
517 * The following routine attempt to work around these limitations present in the
518 * Palm OS API to provide limited dynamic menu support. This solution is far
519 * from perfect, but the only other option is to wait for PalmSource to add full
520 * dynamic menu support, or to recreate the Palm OS menu system from scratch.
522 * This system is limited in that no more than 4 drop-down menus are allowed per
523 * menu bar, and the label for each drop-down menu is limited to 8 characters of
524 * text. However, this menu system should work for most applications.
526 * Basically the menu routines select one of four menu bars, depending on
527 * whether or not the requested menu bar has one, two, three, or four drop-down
530 * These four "template" menu bars contain one, two, three, or four drop-down
531 * menus. Each menu has a dummy menu item attached to it to allow the Palm OS
532 * MenuAddItem function to add the real items.
534 * The labels on the drop-down menus are then replaced with the labels of the
537 * The menu is then attached to the active window and the MenuAddItem API
538 * function is called to add the items to each drop-down menu. Finally,
539 * MenuHideItem is called to remove the dummy items from each drop-down menu.
541 void wxMenuBar::LoadMenu()
546 // Handle to the currently running application database
549 // Get app database reference - needed for some Palm OS Menu API calls.
550 SysGetModuleDatabase(SysGetRefNum(), NULL
, &AppDB
);
551 #endif // __WXPALMOS6__
553 // Get the number of menus
554 int NumMenus
=GetMenuCount();
556 // Set up the pointers and handles
557 char *PalmOSMenuBarPtr
;
558 MemHandle PalmOSMenuBar
;
560 // Load the menu template and set up the menu pointers
563 PalmOSMenuBar
= POS_DmGetResource (AppDB
, MenuRscType
, 1000);
564 PalmOSMenuBarPtr
= (char *)MemHandleLock (PalmOSMenuBar
);
566 PalmOSMenuBarPtr
+= 74;
570 PalmOSMenuBar
= POS_DmGetResource (AppDB
, MenuRscType
, 2000);
571 PalmOSMenuBarPtr
= (char *)MemHandleLock (PalmOSMenuBar
);
573 PalmOSMenuBarPtr
+= 116;
577 PalmOSMenuBar
= POS_DmGetResource (AppDB
, MenuRscType
, 3000);
578 PalmOSMenuBarPtr
= (char *)MemHandleLock (PalmOSMenuBar
);
580 PalmOSMenuBarPtr
+= 158;
584 // We support a maximum of 4 menus, so make sure that do not create
585 // more than we can handle.
588 PalmOSMenuBar
= POS_DmGetResource (AppDB
, MenuRscType
, 4000);
589 PalmOSMenuBarPtr
= (char *)MemHandleLock (PalmOSMenuBar
);
591 PalmOSMenuBarPtr
+= 200;
594 // Set the proper names for the drop-down triggers.
595 for(i
=0;i
<NumMenus
;i
++)
597 // Clear out the old label
598 char buffer
[8]={' ',' ',' ',' ',' ',' ',' ',' '};
599 MemMove(PalmOSMenuBarPtr
,buffer
,8);
601 wxString MenuTitle
=m_titles
.Item(i
);
603 // Make sure we don't copy more than 8 bytes for the label
604 int LengthToCopy
= MenuTitle
.length();
608 MemMove(PalmOSMenuBarPtr
,(char*)(&MenuTitle
),LengthToCopy
);
609 PalmOSMenuBarPtr
+=11;
612 // We are done with the menu pointer.
613 MemHandleUnlock(PalmOSMenuBar
);
614 DmReleaseResource(PalmOSMenuBar
);
616 // We must make the menu active before we can add items to the drop-down
618 POS_FrmSetMenu (FrmGetActiveForm(), AppDB
, NumMenus
* 1000);
620 /* Add the menu items to the drop-down triggers. This must be done after
621 * setting the triggers, because setting the names of drop-down triggers
622 * that have a variable number of items requires carefull calculation of
623 * the offsets in the MenuBarType structure. Setting the triggers first
626 for(i
=0;i
<NumMenus
;i
++)
628 wxMenu
*CurrentMenu
=GetMenu(i
);
630 for(j
=0;j
<CurrentMenu
->GetMenuItemCount();j
++)
632 wxMenuItem
*CurrentItem
=CurrentMenu
->FindItemByPosition(j
);
633 wxString ItemLabel
=CurrentItem
->GetLabel();
635 if(CurrentItem
->IsSeparator()==true)
637 char Separator
=MenuSeparatorChar
;
639 MenuAddItem(9000+i
,((i
*1000)+1000)+j
,0x00,&Separator
);
641 MenuAddItem(((i
*1000)+1000)+j
-1,((i
*1000)+1000)+j
,0x00,&Separator
);
646 MenuAddItem(9000+i
,((i
*1000)+1000)+j
,0x00,(char *)(&ItemLabel
));
648 MenuAddItem(((i
*1000)+1000)+j
-1,((i
*1000)+1000)+j
,0x00,(char *)(&ItemLabel
));
652 // Hide the dummy menu item, since we don't need it anymore.
653 MenuHideItem(9000+i
);
657 void wxMenuBar::Attach(wxFrame
*frame
)
659 // before attaching preprocess menus to not include wxID_EXIT item
660 // as PalmOS guidelines suggest
666 while( item
= FindItem(wxID_EXIT
) )
668 menu
= item
->GetMenu();
669 if( !menu
) break; // something broken ?
671 size_t count
= menu
->GetMenuItemCount();
672 if( count
== 0 ) break; // something broken ?
674 // if EXIT is last item in menu
675 if( menu
->FindItemByPosition( count
- 1 ) == item
)
677 menu
->Destroy( item
);
679 // was more than one item?
680 // was previous separator ?
683 item
= menu
->FindItemByPosition( count
- 2 );
684 if(item
&& item
->IsSeparator())
685 menu
->Destroy( item
);
689 // if EXIT is first item in menu
690 else if( menu
->FindItemByPosition( 0 ) == item
)
692 menu
->Destroy( item
);
694 // was more than one item?
695 // was previous separator ?
698 item
= menu
->FindItemByPosition( 0 );
699 if(item
&& item
->IsSeparator())
700 menu
->Destroy( item
);
704 // if EXIT is in the middle but before and after are selectors
707 i
= 1; // 0 case already done
708 while ( (i
< count
) && (menu
->FindItemByPosition( 0 ) != item
) )
713 if (i
>= count
) break;
714 if (menu
->FindItemByPosition( i
) != item
) break;
715 menu
->Destroy( item
);
716 item
= menu
->FindItemByPosition( i
);
718 item
->IsSeparator() &&
719 menu
->FindItemByPosition( i
-1 )->IsSeparator() )
721 // noe need for two neighbouring separators
722 menu
->Destroy( item
);
727 // check if we received any empty menu!
729 while(i
< GetMenuCount())
733 if( menu
&& (menu
->GetMenuItemCount()==0) )
742 wxMenuBarBase::Attach(frame
);
747 void wxMenuBar::Detach()
749 wxMenuBarBase::Detach();
752 #endif // wxUSE_MENUS