]> git.saurik.com Git - wxWidgets.git/blob - src/palmos/menu.cpp
The wxGNOME whitepaper-to-be.
[wxWidgets.git] / src / palmos / menu.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: menu.cpp
3 // Purpose: wxMenu, wxMenuBar, wxMenuItem
4 // Author: William Osborne
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 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "menu.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28 #pragma hdrstop
29 #endif
30
31 #if wxUSE_MENUS
32
33 #ifndef WX_PRECOMP
34 #include "wx/frame.h"
35 #include "wx/menu.h"
36 #include "wx/utils.h"
37 #include "wx/intl.h"
38 #include "wx/log.h"
39 #endif
40
41 #if wxUSE_OWNER_DRAWN
42 #include "wx/ownerdrw.h"
43 #endif
44
45 // other standard headers
46 #include <string.h>
47
48 #ifdef __PALMOS__
49 #include <PalmOS.h>
50 #include <Menu.h>
51 #endif
52
53 // ----------------------------------------------------------------------------
54 // global variables
55 // ----------------------------------------------------------------------------
56
57 extern wxMenu *wxCurrentPopupMenu;
58
59 // ----------------------------------------------------------------------------
60 // constants
61 // ----------------------------------------------------------------------------
62
63 // the (popup) menu title has this special id
64 static const int idMenuTitle = -3;
65
66 // ----------------------------------------------------------------------------
67 // private functions
68 // ----------------------------------------------------------------------------
69
70 // ============================================================================
71 // implementation
72 // ============================================================================
73
74 #include <wx/listimpl.cpp>
75
76 WX_DEFINE_LIST( wxMenuInfoList ) ;
77
78 #if wxUSE_EXTENDED_RTTI
79
80 WX_DEFINE_FLAGS( wxMenuStyle )
81
82 wxBEGIN_FLAGS( wxMenuStyle )
83 wxFLAGS_MEMBER(wxMENU_TEAROFF)
84 wxEND_FLAGS( wxMenuStyle )
85
86 IMPLEMENT_DYNAMIC_CLASS_XTI(wxMenu, wxEvtHandler,"wx/menu.h")
87
88 wxCOLLECTION_TYPE_INFO( wxMenuItem * , wxMenuItemList ) ;
89
90 template<> void wxCollectionToVariantArray( wxMenuItemList const &theList, wxxVariantArray &value)
91 {
92 wxListCollectionToVariantArray<wxMenuItemList::compatibility_iterator>( theList , value ) ;
93 }
94
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()
101
102 wxBEGIN_HANDLERS_TABLE(wxMenu)
103 wxEND_HANDLERS_TABLE()
104
105 wxDIRECT_CONSTRUCTOR_2( wxMenu , wxString , Title , long , MenuStyle )
106
107 WX_DEFINE_FLAGS( wxMenuBarStyle )
108
109 wxBEGIN_FLAGS( wxMenuBarStyle )
110 wxFLAGS_MEMBER(wxMB_DOCKABLE)
111 wxEND_FLAGS( wxMenuBarStyle )
112
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 & )
115 {
116 return true ;
117 }
118
119 IMPLEMENT_DYNAMIC_CLASS_XTI_CALLBACK(wxMenuBar, wxWindow ,"wx/menu.h",wxMenuBarStreamingCallback)
120
121 IMPLEMENT_DYNAMIC_CLASS_XTI(wxMenuInfo, wxObject , "wx/menu.h" )
122
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()
127
128 wxBEGIN_HANDLERS_TABLE(wxMenuInfo)
129 wxEND_HANDLERS_TABLE()
130
131 wxCONSTRUCTOR_2( wxMenuInfo , wxMenu* , Menu , wxString , Title )
132
133 wxCOLLECTION_TYPE_INFO( wxMenuInfo * , wxMenuInfoList ) ;
134
135 template<> void wxCollectionToVariantArray( wxMenuInfoList const &theList, wxxVariantArray &value)
136 {
137 wxListCollectionToVariantArray<wxMenuInfoList::compatibility_iterator>( theList , value ) ;
138 }
139
140 wxBEGIN_PROPERTIES_TABLE(wxMenuBar)
141 wxPROPERTY_COLLECTION( MenuInfos , wxMenuInfoList , wxMenuInfo* , Append , GetMenuInfos , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
142 wxEND_PROPERTIES_TABLE()
143
144 wxBEGIN_HANDLERS_TABLE(wxMenuBar)
145 wxEND_HANDLERS_TABLE()
146
147 wxCONSTRUCTOR_DUMMY( wxMenuBar )
148
149 #else
150 IMPLEMENT_DYNAMIC_CLASS(wxMenu, wxEvtHandler)
151 IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxWindow)
152 IMPLEMENT_DYNAMIC_CLASS(wxMenuInfo, wxObject)
153 #endif
154
155 const wxMenuInfoList& wxMenuBar::GetMenuInfos() const
156 {
157 wxMenuInfoList* list = const_cast< wxMenuInfoList* >( &m_menuInfos ) ;
158 WX_CLEAR_LIST( wxMenuInfoList , *list ) ;
159 for( size_t i = 0 ; i < GetMenuCount() ; ++i )
160 {
161 wxMenuInfo* info = new wxMenuInfo() ;
162 info->Create( const_cast<wxMenuBar*>(this)->GetMenu(i) , GetLabelTop(i) ) ;
163 list->Append( info ) ;
164 }
165 return m_menuInfos ;
166 }
167
168 // ---------------------------------------------------------------------------
169 // wxMenu construction, adding and removing menu items
170 // ---------------------------------------------------------------------------
171
172 // Construct a menu with optional title (then use append)
173 void wxMenu::Init()
174 {
175 }
176
177 // The wxWindow destructor will take care of deleting the submenus.
178 wxMenu::~wxMenu()
179 {
180 }
181
182 void wxMenu::Break()
183 {
184 }
185
186 void wxMenu::Attach(wxMenuBarBase *menubar)
187 {
188 wxMenuBase::Attach(menubar);
189 }
190
191 #if wxUSE_ACCEL
192
193 int wxMenu::FindAccel(int id) const
194 {
195 return wxNOT_FOUND;
196 }
197
198 void wxMenu::UpdateAccel(wxMenuItem *item)
199 {
200 }
201
202 #endif // wxUSE_ACCEL
203
204 // append a new item or submenu to the menu
205 bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos)
206 {
207 if ( IsAttached() && GetMenuBar()->IsAttached() )
208 {
209 // Regenerate the menu resource
210 GetMenuBar()->Refresh();
211 }
212
213 return TRUE;
214 }
215
216 void wxMenu::EndRadioGroup()
217 {
218 }
219
220 wxMenuItem* wxMenu::DoAppend(wxMenuItem *item)
221 {
222 wxCHECK_MSG( item, NULL, _T("NULL item in wxMenu::DoAppend") );
223
224 if(!wxMenuBase::DoAppend(item) || !DoInsertOrAppend(item))
225 {
226 return NULL;
227 }
228 else if(IsAttached() && GetMenuBar()->IsAttached())
229 {
230 // Regenerate the menu resource
231 GetMenuBar()->Refresh();
232 }
233
234 return item;
235 }
236
237 wxMenuItem* wxMenu::DoInsert(size_t pos, wxMenuItem *item)
238 {
239 if (wxMenuBase::DoInsert(pos, item) && DoInsertOrAppend(item, pos))
240 return item;
241 else
242 return NULL;
243 }
244
245 wxMenuItem *wxMenu::DoRemove(wxMenuItem *item)
246 {
247 // we need to find the items position in the child list
248 size_t pos;
249 wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst();
250 for ( pos = 0; node; pos++ )
251 {
252 if ( node->GetData() == item )
253 break;
254
255 node = node->GetNext();
256 }
257
258 // DoRemove() (unlike Remove) can only be called for existing item!
259 wxCHECK_MSG( node, NULL, wxT("bug in wxMenu::Remove logic") );
260
261 // remove the item from the menu
262 wxMenuItem *ret=wxMenuBase::DoRemove(item);
263
264 if ( IsAttached() && GetMenuBar()->IsAttached() )
265 {
266 // Regenerate the menu resource
267 GetMenuBar()->Refresh();
268 }
269
270 return ret;
271 }
272
273 // ---------------------------------------------------------------------------
274 // accelerator helpers
275 // ---------------------------------------------------------------------------
276
277 #if wxUSE_ACCEL
278
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
282 {
283 size_t count = GetAccelCount();
284 for ( size_t n = 0; n < count; n++ )
285 {
286 *accels++ = *m_accels[n];
287 }
288
289 return count;
290 }
291
292 #endif // wxUSE_ACCEL
293
294 // ---------------------------------------------------------------------------
295 // set wxMenu title
296 // ---------------------------------------------------------------------------
297
298 void wxMenu::SetTitle(const wxString& label)
299 {
300 m_title = label;
301
302 if ( IsAttached() && GetMenuBar()->IsAttached() )
303 {
304 // Regenerate the menu resource
305 GetMenuBar()->Refresh();
306 }
307 }
308
309 // ---------------------------------------------------------------------------
310 // event processing
311 // ---------------------------------------------------------------------------
312
313 bool wxMenu::PalmCommand(WXUINT WXUNUSED(param), WXWORD id)
314 {
315 return false;
316 }
317
318 // ---------------------------------------------------------------------------
319 // other
320 // ---------------------------------------------------------------------------
321
322 wxWindow *wxMenu::GetWindow() const
323 {
324 return NULL;
325 }
326
327 // ---------------------------------------------------------------------------
328 // Menu Bar
329 // ---------------------------------------------------------------------------
330
331 void wxMenuBar::Init()
332 {
333 }
334
335 wxMenuBar::wxMenuBar()
336 {
337 }
338
339 wxMenuBar::wxMenuBar( long WXUNUSED(style) )
340 {
341 }
342
343 wxMenuBar::wxMenuBar(int count, wxMenu *menus[], const wxString titles[])
344 {
345 }
346
347 wxMenuBar::~wxMenuBar()
348 {
349 }
350
351 // ---------------------------------------------------------------------------
352 // wxMenuBar helpers
353 // ---------------------------------------------------------------------------
354
355 void wxMenuBar::Refresh()
356 {
357 wxCHECK_RET( IsAttached(), wxT("can't refresh unattached menubar") );
358
359 // Regenerate the menu resource
360 LoadMenu();
361 }
362
363 WXHMENU wxMenuBar::Create()
364 {
365 return NULL;
366 }
367
368 int wxMenuBar::PalmPositionForWxMenu(wxMenu *menu, int wxpos)
369 {
370 return -1;
371 }
372
373 // ---------------------------------------------------------------------------
374 // wxMenuBar functions to work with the top level submenus
375 // ---------------------------------------------------------------------------
376
377 void wxMenuBar::EnableTop(size_t pos, bool enable)
378 {
379 // Palm OS does not have support for grayed or disabled items
380 }
381
382 void wxMenuBar::SetLabelTop(size_t pos, const wxString& label)
383 {
384 wxCHECK_RET( pos < GetMenuCount(), wxT("invalid menu index") );
385
386 m_titles[pos]=wxStripMenuCodes(label);
387
388 if ( !IsAttached() )
389 {
390 return;
391 }
392
393 // Regenerate the menu resource
394 Refresh();
395 }
396
397 wxString wxMenuBar::GetLabelTop(size_t pos) const
398 {
399 wxCHECK_MSG( pos < GetMenuCount(), wxEmptyString,
400 wxT("invalid menu index in wxMenuBar::GetLabelTop") );
401
402 return wxMenuItem::GetLabelFromText(m_titles[pos]);
403 }
404
405 // ---------------------------------------------------------------------------
406 // wxMenuBar construction
407 // ---------------------------------------------------------------------------
408
409 wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title)
410 {
411 wxMenu *menuOld = wxMenuBarBase::Replace(pos, menu, title);
412 if ( !menuOld )
413 return NULL;
414
415 m_titles[pos]=wxStripMenuCodes(title);
416
417 if ( IsAttached() )
418 {
419 // Regenerate the menu resource
420 Refresh();
421 }
422
423 return menuOld;
424 }
425
426 bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title)
427 {
428 if ( !wxMenuBarBase::Insert(pos, menu, title) )
429 return FALSE;
430
431 m_titles.Insert(wxStripMenuCodes(title), pos);
432
433 if ( IsAttached() )
434 {
435 // Regenerate the menu resource
436 Refresh();
437 }
438
439 return TRUE;
440 }
441
442 bool wxMenuBar::Append(wxMenu *menu, const wxString& title)
443 {
444 if ( !wxMenuBarBase::Append(menu, title) )
445 return FALSE;
446
447 m_titles.Add(wxStripMenuCodes(title));
448
449 if(IsAttached())
450 {
451 // Regenerate the menu resource
452 Refresh();
453 }
454
455 return TRUE;
456 }
457
458 wxMenu *wxMenuBar::Remove(size_t pos)
459 {
460 wxMenu *menu = wxMenuBarBase::Remove(pos);
461 if ( !menu )
462 return NULL;
463
464 m_titles.RemoveAt(pos);
465
466 if (IsAttached())
467 {
468 // Regenerate the menu resource
469 Refresh();
470 }
471
472 return menu;
473 }
474
475 #if wxUSE_ACCEL
476
477 void wxMenuBar::RebuildAccelTable()
478 {
479 }
480
481 #endif // wxUSE_ACCEL
482
483 int wxMenuBar::ProcessCommand(int ItemID)
484 {
485 if(!IsAttached())
486 return -1;
487
488 int MenuNum=(ItemID/1000)-1;
489 int ItemNum=(ItemID-(1000*(MenuNum+1)));
490
491 // Should never happen, but it doesn't hurt to check anyway.
492 if(MenuNum>GetMenuCount())
493 return -1;
494
495 // Get the menu
496 wxMenu *ActiveMenu=GetMenu(MenuNum);
497
498 // Make sure this is a valid item.
499 if(ItemNum>ActiveMenu->GetMenuItemCount())
500 return -1;
501
502 // Get the item
503 wxMenuItem *ActiveItem=ActiveMenu->FindItemByPosition(ItemNum);
504 int ActiveID=ActiveItem->GetId();
505
506 return ActiveID;
507 }
508
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.
513 *
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.
518 *
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.
523 *
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.
527 *
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
530 * menus.
531 *
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.
535 *
536 * The labels on the drop-down menus are then replaced with the labels of the
537 * real menus.
538 *
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.
542 */
543 void wxMenuBar::LoadMenu()
544 {
545 int i=0;
546 int j=0;
547
548 // Handle to the currently running application database
549 DmOpenRef AppDB;
550
551 // Get app database reference - needed for some Palm OS Menu API calls.
552 SysGetModuleDatabase(SysGetRefNum(), NULL, &AppDB);
553
554 // Get the number of menus
555 int NumMenus=GetMenuCount();
556
557 // Set up the pointers and handles
558 char *PalmOSMenuBarPtr;
559 MemHandle PalmOSMenuBar;
560
561 // Load the menu template and set up the menu pointers
562 if(NumMenus==1)
563 {
564 PalmOSMenuBar=DmGetResource(AppDB,'MBAR',1000);
565 PalmOSMenuBarPtr=(char *)MemHandleLock(PalmOSMenuBar);
566
567 PalmOSMenuBarPtr+=74;
568 }
569 else if(NumMenus==2)
570 {
571 PalmOSMenuBar=DmGetResource(AppDB,'MBAR',2000);
572 PalmOSMenuBarPtr=(char *)MemHandleLock(PalmOSMenuBar);
573
574 PalmOSMenuBarPtr+=116;
575 }
576 else if(NumMenus==3)
577 {
578 PalmOSMenuBar=DmGetResource(AppDB,'MBAR',3000);
579 PalmOSMenuBarPtr=(char *)MemHandleLock(PalmOSMenuBar);
580
581 PalmOSMenuBarPtr+=158;
582 }
583 else
584 {
585 // We support a maximum of 4 menus, so make sure that do not create
586 // more than we can handle.
587 NumMenus=4;
588
589 PalmOSMenuBar=DmGetResource(AppDB,'MBAR',4000);
590 PalmOSMenuBarPtr=(char *)MemHandleLock(PalmOSMenuBar);
591
592 PalmOSMenuBarPtr+=200;
593 }
594
595 // Set the proper names for the drop-down triggers.
596 for(i=0;i<NumMenus;i++)
597 {
598 // Clear out the old label
599 char buffer[8]={' ',' ',' ',' ',' ',' ',' ',' '};
600 MemMove(PalmOSMenuBarPtr,buffer,8);
601
602 wxString MenuTitle=m_titles.Item(i);
603
604 // Make sure we don't copy more than 8 bytes for the label
605 int LengthToCopy=MenuTitle.length();
606 if(LengthToCopy>8)
607 LengthToCopy=8;
608
609 MemMove(PalmOSMenuBarPtr,MenuTitle,LengthToCopy);
610 PalmOSMenuBarPtr+=11;
611 }
612
613 // We are done with the menu pointer.
614 MemHandleUnlock(PalmOSMenuBar);
615 DmReleaseResource(PalmOSMenuBar);
616
617 // We must make the menu active before we can add items to the drop-down
618 // triggers.
619 FrmSetMenu(FrmGetActiveForm(),AppDB,NumMenus*1000);
620
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
625 * avoids this.
626 */
627 for(i=0;i<NumMenus;i++)
628 {
629 wxMenu *CurrentMenu=GetMenu(i);
630
631 for(j=0;j<CurrentMenu->GetMenuItemCount();j++)
632 {
633 wxMenuItem *CurrentItem=CurrentMenu->FindItemByPosition(j);
634 wxString ItemLabel=CurrentItem->GetLabel();
635
636 if(CurrentItem->IsSeparator()==true)
637 {
638 char Separator=MenuSeparatorChar;
639 if(j==0)
640 MenuAddItem(9000+i,((i*1000)+1000)+j,0x00,&Separator);
641 else
642 MenuAddItem(((i*1000)+1000)+j-1,((i*1000)+1000)+j,0x00,&Separator);
643 }
644 else
645 {
646 if(j==0)
647 MenuAddItem(9000+i,((i*1000)+1000)+j,0x00,ItemLabel);
648 else
649 MenuAddItem(((i*1000)+1000)+j-1,((i*1000)+1000)+j,0x00,ItemLabel);
650 }
651 }
652
653 // Hide the dummy menu item, since we don't need it anymore.
654 MenuHideItem(9000+i);
655 }
656 }
657
658 void wxMenuBar::Attach(wxFrame *frame)
659 {
660 wxMenuBarBase::Attach(frame);
661
662 LoadMenu();
663 }
664
665 #if defined(__WXWINCE__) && (_WIN32_WCE >= 400 && !defined(__POCKETPC__) && !defined(__SMARTPHONE__))
666 bool wxMenuBar::AddAdornments(long style)
667 {
668 return false;
669 }
670 #endif
671
672 void wxMenuBar::Detach()
673 {
674 wxMenuBarBase::Detach();
675 }
676
677 #endif // wxUSE_MENUS