]> git.saurik.com Git - wxWidgets.git/blame - src/palmos/menu.cpp
reverted Robert's over-optimisation, correct fix coming soon
[wxWidgets.git] / src / palmos / menu.cpp
CommitLineData
ffecfa5a
JS
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
57extern wxMenu *wxCurrentPopupMenu;
58
59// ----------------------------------------------------------------------------
60// constants
61// ----------------------------------------------------------------------------
62
63// the (popup) menu title has this special id
64static const int idMenuTitle = -3;
65
66// ----------------------------------------------------------------------------
67// private functions
68// ----------------------------------------------------------------------------
69
70// ============================================================================
71// implementation
72// ============================================================================
73
74#include <wx/listimpl.cpp>
75
76WX_DEFINE_LIST( wxMenuInfoList ) ;
77
78#if wxUSE_EXTENDED_RTTI
79
80WX_DEFINE_FLAGS( wxMenuStyle )
81
82wxBEGIN_FLAGS( wxMenuStyle )
83 wxFLAGS_MEMBER(wxMENU_TEAROFF)
84wxEND_FLAGS( wxMenuStyle )
85
86IMPLEMENT_DYNAMIC_CLASS_XTI(wxMenu, wxEvtHandler,"wx/menu.h")
87
88wxCOLLECTION_TYPE_INFO( wxMenuItem * , wxMenuItemList ) ;
89
90template<> void wxCollectionToVariantArray( wxMenuItemList const &theList, wxxVariantArray &value)
91{
92 wxListCollectionToVariantArray<wxMenuItemList::compatibility_iterator>( theList , value ) ;
93}
94
95wxBEGIN_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"))
100wxEND_PROPERTIES_TABLE()
101
102wxBEGIN_HANDLERS_TABLE(wxMenu)
103wxEND_HANDLERS_TABLE()
104
105wxDIRECT_CONSTRUCTOR_2( wxMenu , wxString , Title , long , MenuStyle )
106
107WX_DEFINE_FLAGS( wxMenuBarStyle )
108
109wxBEGIN_FLAGS( wxMenuBarStyle )
110 wxFLAGS_MEMBER(wxMB_DOCKABLE)
111wxEND_FLAGS( wxMenuBarStyle )
112
113// the negative id would lead the window (its superclass !) to vetoe streaming out otherwise
114bool wxMenuBarStreamingCallback( const wxObject *WXUNUSED(object), wxWriter * , wxPersister * , wxxVariantArray & )
115{
116 return true ;
117}
118
119IMPLEMENT_DYNAMIC_CLASS_XTI_CALLBACK(wxMenuBar, wxWindow ,"wx/menu.h",wxMenuBarStreamingCallback)
120
121IMPLEMENT_DYNAMIC_CLASS_XTI(wxMenuInfo, wxObject , "wx/menu.h" )
122
123wxBEGIN_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"))
126wxEND_PROPERTIES_TABLE()
127
128wxBEGIN_HANDLERS_TABLE(wxMenuInfo)
129wxEND_HANDLERS_TABLE()
130
131wxCONSTRUCTOR_2( wxMenuInfo , wxMenu* , Menu , wxString , Title )
132
133wxCOLLECTION_TYPE_INFO( wxMenuInfo * , wxMenuInfoList ) ;
134
135template<> void wxCollectionToVariantArray( wxMenuInfoList const &theList, wxxVariantArray &value)
136{
137 wxListCollectionToVariantArray<wxMenuInfoList::compatibility_iterator>( theList , value ) ;
138}
139
140wxBEGIN_PROPERTIES_TABLE(wxMenuBar)
141 wxPROPERTY_COLLECTION( MenuInfos , wxMenuInfoList , wxMenuInfo* , Append , GetMenuInfos , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
142wxEND_PROPERTIES_TABLE()
143
144wxBEGIN_HANDLERS_TABLE(wxMenuBar)
145wxEND_HANDLERS_TABLE()
146
147wxCONSTRUCTOR_DUMMY( wxMenuBar )
148
149#else
150IMPLEMENT_DYNAMIC_CLASS(wxMenu, wxEvtHandler)
151IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxWindow)
152IMPLEMENT_DYNAMIC_CLASS(wxMenuInfo, wxObject)
153#endif
154
155const 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)
173void wxMenu::Init()
174{
175}
176
177// The wxWindow destructor will take care of deleting the submenus.
178wxMenu::~wxMenu()
179{
180}
181
182void wxMenu::Break()
183{
184}
185
186void wxMenu::Attach(wxMenuBarBase *menubar)
187{
188 wxMenuBase::Attach(menubar);
189}
190
191#if wxUSE_ACCEL
192
193int wxMenu::FindAccel(int id) const
194{
195 return wxNOT_FOUND;
196}
197
198void wxMenu::UpdateAccel(wxMenuItem *item)
199{
200}
201
202#endif // wxUSE_ACCEL
203
204// append a new item or submenu to the menu
205bool 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
216void wxMenu::EndRadioGroup()
217{
218}
219
220wxMenuItem* 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
237wxMenuItem* 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
245wxMenuItem *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
281size_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
298void 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
313bool wxMenu::PalmCommand(WXUINT WXUNUSED(param), WXWORD id)
314{
315 return false;
316}
317
318// ---------------------------------------------------------------------------
319// other
320// ---------------------------------------------------------------------------
321
322wxWindow *wxMenu::GetWindow() const
323{
324 return NULL;
325}
326
327// ---------------------------------------------------------------------------
328// Menu Bar
329// ---------------------------------------------------------------------------
330
331void wxMenuBar::Init()
332{
333}
334
335wxMenuBar::wxMenuBar()
336{
337}
338
339wxMenuBar::wxMenuBar( long WXUNUSED(style) )
340{
341}
342
343wxMenuBar::wxMenuBar(int count, wxMenu *menus[], const wxString titles[])
344{
345}
346
347wxMenuBar::~wxMenuBar()
348{
349}
350
351// ---------------------------------------------------------------------------
352// wxMenuBar helpers
353// ---------------------------------------------------------------------------
354
355void wxMenuBar::Refresh()
356{
357 wxCHECK_RET( IsAttached(), wxT("can't refresh unattached menubar") );
358
359 // Regenerate the menu resource
360 LoadMenu();
361}
362
363WXHMENU wxMenuBar::Create()
364{
365 return NULL;
366}
367
368int 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
377void wxMenuBar::EnableTop(size_t pos, bool enable)
378{
379 // Palm OS does not have support for grayed or disabled items
380}
381
382void 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
397wxString 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
409wxMenu *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
426bool 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
442bool 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
458wxMenu *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
477void wxMenuBar::RebuildAccelTable()
478{
479}
480
481#endif // wxUSE_ACCEL
482
483int 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 */
543void 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
658void 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__))
666bool wxMenuBar::AddAdornments(long style)
667{
668 return false;
669}
670#endif
671
672void wxMenuBar::Detach()
673{
674 wxMenuBarBase::Detach();
675}
676
677#endif // wxUSE_MENUS