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 // ---------------------------------------------------------------------------
73 // wxMenu construction, adding and removing menu items
74 // ---------------------------------------------------------------------------
76 // Construct a menu with optional title (then use append)
81 // The wxWindow destructor will take care of deleting the submenus.
90 void wxMenu::Attach(wxMenuBarBase
*menubar
)
92 wxMenuBase::Attach(menubar
);
97 int wxMenu::FindAccel(int id
) const
102 void wxMenu::UpdateAccel(wxMenuItem
*item
)
106 #endif // wxUSE_ACCEL
108 // append a new item or submenu to the menu
109 bool wxMenu::DoInsertOrAppend(wxMenuItem
*pItem
, size_t pos
)
111 if ( IsAttached() && GetMenuBar()->IsAttached() )
113 // Regenerate the menu resource
114 GetMenuBar()->Refresh();
120 void wxMenu::EndRadioGroup()
124 wxMenuItem
* wxMenu::DoAppend(wxMenuItem
*item
)
126 wxCHECK_MSG( item
, NULL
, wxT("NULL item in wxMenu::DoAppend") );
128 if(!wxMenuBase::DoAppend(item
) || !DoInsertOrAppend(item
))
132 else if(IsAttached() && GetMenuBar()->IsAttached())
134 // Regenerate the menu resource
135 GetMenuBar()->Refresh();
141 wxMenuItem
* wxMenu::DoInsert(size_t pos
, wxMenuItem
*item
)
143 if (wxMenuBase::DoInsert(pos
, item
) && DoInsertOrAppend(item
, pos
))
149 wxMenuItem
*wxMenu::DoRemove(wxMenuItem
*item
)
151 // we need to find the items position in the child list
153 wxMenuItemList::compatibility_iterator node
= GetMenuItems().GetFirst();
154 for ( pos
= 0; node
; pos
++ )
156 if ( node
->GetData() == item
)
159 node
= node
->GetNext();
162 // DoRemove() (unlike Remove) can only be called for existing item!
163 wxCHECK_MSG( node
, NULL
, wxT("bug in wxMenu::Remove logic") );
165 // remove the item from the menu
166 wxMenuItem
*ret
=wxMenuBase::DoRemove(item
);
168 if ( IsAttached() && GetMenuBar()->IsAttached() )
170 // Regenerate the menu resource
171 GetMenuBar()->Refresh();
177 // ---------------------------------------------------------------------------
178 // accelerator helpers
179 // ---------------------------------------------------------------------------
183 // create the wxAcceleratorEntries for our accels and put them into provided
184 // array - return the number of accels we have
185 size_t wxMenu::CopyAccels(wxAcceleratorEntry
*accels
) const
187 size_t count
= GetAccelCount();
188 for ( size_t n
= 0; n
< count
; n
++ )
190 *accels
++ = *m_accels
[n
];
196 #endif // wxUSE_ACCEL
198 // ---------------------------------------------------------------------------
200 // ---------------------------------------------------------------------------
202 void wxMenu::SetTitle(const wxString
& label
)
206 if ( IsAttached() && GetMenuBar()->IsAttached() )
208 // Regenerate the menu resource
209 GetMenuBar()->Refresh();
213 // ---------------------------------------------------------------------------
215 // ---------------------------------------------------------------------------
217 bool wxMenu::PalmCommand(WXUINT
WXUNUSED(param
), WXWORD id
)
222 // ---------------------------------------------------------------------------
224 // ---------------------------------------------------------------------------
226 wxWindow
*wxMenu::GetWindow() const
231 // ---------------------------------------------------------------------------
233 // ---------------------------------------------------------------------------
235 void wxMenuBar::Init()
239 wxMenuBar::wxMenuBar()
243 wxMenuBar::wxMenuBar( long WXUNUSED(style
) )
247 wxMenuBar::wxMenuBar(size_t count
, wxMenu
*menus
[], const wxString titles
[], long WXUNUSED(style
))
251 wxMenuBar::~wxMenuBar()
255 // ---------------------------------------------------------------------------
257 // ---------------------------------------------------------------------------
259 void wxMenuBar::Refresh()
261 wxCHECK_RET( IsAttached(), wxT("can't refresh unattached menubar") );
263 // Regenerate the menu resource
267 WXHMENU
wxMenuBar::Create()
272 int wxMenuBar::PalmPositionForWxMenu(wxMenu
*menu
, int wxpos
)
277 // ---------------------------------------------------------------------------
278 // wxMenuBar functions to work with the top level submenus
279 // ---------------------------------------------------------------------------
281 void wxMenuBar::EnableTop(size_t pos
, bool enable
)
283 // Palm OS does not have support for grayed or disabled items
286 void wxMenuBar::SetMenuLabel(size_t pos
, const wxString
& label
)
288 wxCHECK_RET( pos
< GetMenuCount(), wxT("invalid menu index") );
290 m_titles
[pos
] = label
;
297 // Regenerate the menu resource
301 wxString
wxMenuBar::GetMenuLabel(size_t pos
) const
303 wxCHECK_MSG( pos
< GetMenuCount(), wxEmptyString
,
304 wxT("invalid menu index in wxMenuBar::GetMenuLabel") );
306 return m_titles
[pos
];
309 // ---------------------------------------------------------------------------
310 // wxMenuBar construction
311 // ---------------------------------------------------------------------------
313 wxMenu
*wxMenuBar::Replace(size_t pos
, wxMenu
*menu
, const wxString
& title
)
315 wxMenu
*menuOld
= wxMenuBarBase::Replace(pos
, menu
, title
);
319 m_titles
[pos
] = title
;
323 // Regenerate the menu resource
330 bool wxMenuBar::Insert(size_t pos
, wxMenu
*menu
, const wxString
& title
)
332 if ( !wxMenuBarBase::Insert(pos
, menu
, title
) )
335 m_titles
.Insert(title
, pos
);
339 // Regenerate the menu resource
346 bool wxMenuBar::Append(wxMenu
*menu
, const wxString
& title
)
348 if ( !wxMenuBarBase::Append(menu
, title
) )
355 // Regenerate the menu resource
362 wxMenu
*wxMenuBar::Remove(size_t pos
)
364 wxMenu
*menu
= wxMenuBarBase::Remove(pos
);
368 m_titles
.RemoveAt(pos
);
372 // Regenerate the menu resource
381 void wxMenuBar::RebuildAccelTable()
385 #endif // wxUSE_ACCEL
387 int wxMenuBar::ProcessCommand(int ItemID
)
392 int MenuNum
=(ItemID
/1000)-1;
393 int ItemNum
=(ItemID
-(1000*(MenuNum
+1)));
395 // Should never happen, but it doesn't hurt to check anyway.
396 if(MenuNum
>GetMenuCount())
400 wxMenu
*ActiveMenu
=GetMenu(MenuNum
);
402 // Make sure this is a valid item.
403 if(ItemNum
>ActiveMenu
->GetMenuItemCount())
407 wxMenuItem
*ActiveItem
=ActiveMenu
->FindItemByPosition(ItemNum
);
408 int ActiveID
=ActiveItem
->GetId();
413 /* Palm OS does not have good dynamic menu support. About all you can do with
414 * the standard API calls is to add new items to an existing drop-down menu and
415 * hide/show items in a drop-down menu. It is impossible to add, hide, or
416 * change the label on a drop-down menu.
418 * The easiest and simplest way around this limitation is to modify the Palm OS
419 * MenuBarType structure directly. This gives limited ability to change the
420 * label on a drop-down menu. I have not been able to find a safe way to add,
421 * delete, or resize drop-down menus in OS 6.
423 * The following routine attempt to work around these limitations present in the
424 * Palm OS API to provide limited dynamic menu support. This solution is far
425 * from perfect, but the only other option is to wait for PalmSource to add full
426 * dynamic menu support, or to recreate the Palm OS menu system from scratch.
428 * This system is limited in that no more than 4 drop-down menus are allowed per
429 * menu bar, and the label for each drop-down menu is limited to 8 characters of
430 * text. However, this menu system should work for most applications.
432 * Basically the menu routines select one of four menu bars, depending on
433 * whether or not the requested menu bar has one, two, three, or four drop-down
436 * These four "template" menu bars contain one, two, three, or four drop-down
437 * menus. Each menu has a dummy menu item attached to it to allow the Palm OS
438 * MenuAddItem function to add the real items.
440 * The labels on the drop-down menus are then replaced with the labels of the
443 * The menu is then attached to the active window and the MenuAddItem API
444 * function is called to add the items to each drop-down menu. Finally,
445 * MenuHideItem is called to remove the dummy items from each drop-down menu.
447 void wxMenuBar::LoadMenu()
452 // Handle to the currently running application database
455 // Get app database reference - needed for some Palm OS Menu API calls.
456 SysGetModuleDatabase(SysGetRefNum(), NULL
, &AppDB
);
457 #endif // __WXPALMOS6__
459 // Get the number of menus
460 int NumMenus
=GetMenuCount();
462 // Set up the pointers and handles
463 char *PalmOSMenuBarPtr
;
464 MemHandle PalmOSMenuBar
;
466 // Load the menu template and set up the menu pointers
469 PalmOSMenuBar
= POS_DmGetResource (AppDB
, MenuRscType
, 1000);
470 PalmOSMenuBarPtr
= (char *)MemHandleLock (PalmOSMenuBar
);
472 PalmOSMenuBarPtr
+= 74;
476 PalmOSMenuBar
= POS_DmGetResource (AppDB
, MenuRscType
, 2000);
477 PalmOSMenuBarPtr
= (char *)MemHandleLock (PalmOSMenuBar
);
479 PalmOSMenuBarPtr
+= 116;
483 PalmOSMenuBar
= POS_DmGetResource (AppDB
, MenuRscType
, 3000);
484 PalmOSMenuBarPtr
= (char *)MemHandleLock (PalmOSMenuBar
);
486 PalmOSMenuBarPtr
+= 158;
490 // We support a maximum of 4 menus, so make sure that do not create
491 // more than we can handle.
494 PalmOSMenuBar
= POS_DmGetResource (AppDB
, MenuRscType
, 4000);
495 PalmOSMenuBarPtr
= (char *)MemHandleLock (PalmOSMenuBar
);
497 PalmOSMenuBarPtr
+= 200;
500 // Set the proper names for the drop-down triggers.
501 for(i
=0;i
<NumMenus
;i
++)
503 // Clear out the old label
504 char buffer
[8]={' ',' ',' ',' ',' ',' ',' ',' '};
505 MemMove(PalmOSMenuBarPtr
,buffer
,8);
507 wxString MenuTitle
=m_titles
.Item(i
);
509 // Make sure we don't copy more than 8 bytes for the label
510 int LengthToCopy
= MenuTitle
.length();
514 MemMove(PalmOSMenuBarPtr
,(char*)(&MenuTitle
),LengthToCopy
);
515 PalmOSMenuBarPtr
+=11;
518 // We are done with the menu pointer.
519 MemHandleUnlock(PalmOSMenuBar
);
520 DmReleaseResource(PalmOSMenuBar
);
522 // We must make the menu active before we can add items to the drop-down
524 POS_FrmSetMenu (FrmGetActiveForm(), AppDB
, NumMenus
* 1000);
526 /* Add the menu items to the drop-down triggers. This must be done after
527 * setting the triggers, because setting the names of drop-down triggers
528 * that have a variable number of items requires carefull calculation of
529 * the offsets in the MenuBarType structure. Setting the triggers first
532 for(i
=0;i
<NumMenus
;i
++)
534 wxMenu
*CurrentMenu
=GetMenu(i
);
536 for(j
=0;j
<CurrentMenu
->GetMenuItemCount();j
++)
538 wxMenuItem
*CurrentItem
=CurrentMenu
->FindItemByPosition(j
);
539 wxString ItemLabel
=CurrentItem
->GetLabel();
541 if(CurrentItem
->IsSeparator()==true)
543 char Separator
=MenuSeparatorChar
;
545 MenuAddItem(9000+i
,((i
*1000)+1000)+j
,0x00,&Separator
);
547 MenuAddItem(((i
*1000)+1000)+j
-1,((i
*1000)+1000)+j
,0x00,&Separator
);
552 MenuAddItem(9000+i
,((i
*1000)+1000)+j
,0x00,(char *)(&ItemLabel
));
554 MenuAddItem(((i
*1000)+1000)+j
-1,((i
*1000)+1000)+j
,0x00,(char *)(&ItemLabel
));
558 // Hide the dummy menu item, since we don't need it anymore.
559 MenuHideItem(9000+i
);
563 void wxMenuBar::Attach(wxFrame
*frame
)
565 // before attaching preprocess menus to not include wxID_EXIT item
566 // as PalmOS guidelines suggest
572 while( item
= FindItem(wxID_EXIT
) )
574 menu
= item
->GetMenu();
575 if( !menu
) break; // something broken ?
577 size_t count
= menu
->GetMenuItemCount();
578 if( count
== 0 ) break; // something broken ?
580 // if EXIT is last item in menu
581 if( menu
->FindItemByPosition( count
- 1 ) == item
)
583 menu
->Destroy( item
);
585 // was more than one item?
586 // was previous separator ?
589 item
= menu
->FindItemByPosition( count
- 2 );
590 if(item
&& item
->IsSeparator())
591 menu
->Destroy( item
);
595 // if EXIT is first item in menu
596 else if( menu
->FindItemByPosition( 0 ) == item
)
598 menu
->Destroy( item
);
600 // was more than one item?
601 // was previous separator ?
604 item
= menu
->FindItemByPosition( 0 );
605 if(item
&& item
->IsSeparator())
606 menu
->Destroy( item
);
610 // if EXIT is in the middle but before and after are selectors
613 i
= 1; // 0 case already done
614 while ( (i
< count
) && (menu
->FindItemByPosition( 0 ) != item
) )
619 if (i
>= count
) break;
620 if (menu
->FindItemByPosition( i
) != item
) break;
621 menu
->Destroy( item
);
622 item
= menu
->FindItemByPosition( i
);
624 item
->IsSeparator() &&
625 menu
->FindItemByPosition( i
-1 )->IsSeparator() )
627 // noe need for two neighbouring separators
628 menu
->Destroy( item
);
633 // check if we received any empty menu!
635 while(i
< GetMenuCount())
639 if( menu
&& (menu
->GetMenuItemCount()==0) )
648 wxMenuBarBase::Attach(frame
);
653 void wxMenuBar::Detach()
655 wxMenuBarBase::Detach();
658 #endif // wxUSE_MENUS