]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/palmos/menu.cpp
Typo
[wxWidgets.git] / src / palmos / menu.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/palmos/menu.cpp
3// Purpose: wxMenu, wxMenuBar, wxMenuItem
4// Author: William Osborne - minimal working wxPalmOS port
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// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
24 #pragma hdrstop
25#endif
26
27#if wxUSE_MENUS
28
29#include "wx/menu.h"
30
31#ifndef WX_PRECOMP
32 #include "wx/frame.h"
33 #include "wx/utils.h"
34 #include "wx/intl.h"
35 #include "wx/log.h"
36#endif
37
38#if wxUSE_OWNER_DRAWN
39 #include "wx/ownerdrw.h"
40#endif
41
42#include <Loader.h>
43#include <Form.h>
44#include <Menu.h>
45
46// ----------------------------------------------------------------------------
47// global variables
48// ----------------------------------------------------------------------------
49
50extern wxMenu *wxCurrentPopupMenu;
51
52// ----------------------------------------------------------------------------
53// constants
54// ----------------------------------------------------------------------------
55
56// the (popup) menu title has this special id
57static const int idMenuTitle = -3;
58
59// ----------------------------------------------------------------------------
60// private functions
61// ----------------------------------------------------------------------------
62
63// ============================================================================
64// implementation
65// ============================================================================
66
67#include "wx/listimpl.cpp"
68
69WX_DEFINE_LIST( wxMenuInfoList )
70
71#if wxUSE_EXTENDED_RTTI
72
73WX_DEFINE_FLAGS( wxMenuStyle )
74
75wxBEGIN_FLAGS( wxMenuStyle )
76 wxFLAGS_MEMBER(wxMENU_TEAROFF)
77wxEND_FLAGS( wxMenuStyle )
78
79IMPLEMENT_DYNAMIC_CLASS_XTI(wxMenu, wxEvtHandler,"wx/menu.h")
80
81wxCOLLECTION_TYPE_INFO( wxMenuItem * , wxMenuItemList ) ;
82
83template<> void wxCollectionToVariantArray( wxMenuItemList const &theList, wxxVariantArray &value)
84{
85 wxListCollectionToVariantArray<wxMenuItemList::compatibility_iterator>( theList , value ) ;
86}
87
88wxBEGIN_PROPERTIES_TABLE(wxMenu)
89 wxEVENT_PROPERTY( Select , wxEVT_COMMAND_MENU_SELECTED , wxCommandEvent)
90 wxPROPERTY( Title, wxString , SetTitle, GetTitle, wxString(), 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
91 wxREADONLY_PROPERTY_FLAGS( MenuStyle , wxMenuStyle , long , GetStyle , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
92 wxPROPERTY_COLLECTION( MenuItems , wxMenuItemList , wxMenuItem* , Append , GetMenuItems , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
93wxEND_PROPERTIES_TABLE()
94
95wxBEGIN_HANDLERS_TABLE(wxMenu)
96wxEND_HANDLERS_TABLE()
97
98wxDIRECT_CONSTRUCTOR_2( wxMenu , wxString , Title , long , MenuStyle )
99
100WX_DEFINE_FLAGS( wxMenuBarStyle )
101
102wxBEGIN_FLAGS( wxMenuBarStyle )
103 wxFLAGS_MEMBER(wxMB_DOCKABLE)
104wxEND_FLAGS( wxMenuBarStyle )
105
106// the negative id would lead the window (its superclass !) to vetoe streaming out otherwise
107bool wxMenuBarStreamingCallback( const wxObject *WXUNUSED(object), wxWriter * , wxPersister * , wxxVariantArray & )
108{
109 return true ;
110}
111
112IMPLEMENT_DYNAMIC_CLASS_XTI_CALLBACK(wxMenuBar, wxWindow ,"wx/menu.h",wxMenuBarStreamingCallback)
113
114IMPLEMENT_DYNAMIC_CLASS_XTI(wxMenuInfo, wxObject , "wx/menu.h" )
115
116wxBEGIN_PROPERTIES_TABLE(wxMenuInfo)
117 wxREADONLY_PROPERTY( Menu , wxMenu* , GetMenu , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
118 wxREADONLY_PROPERTY( Title , wxString , GetTitle , wxString() , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
119wxEND_PROPERTIES_TABLE()
120
121wxBEGIN_HANDLERS_TABLE(wxMenuInfo)
122wxEND_HANDLERS_TABLE()
123
124wxCONSTRUCTOR_2( wxMenuInfo , wxMenu* , Menu , wxString , Title )
125
126wxCOLLECTION_TYPE_INFO( wxMenuInfo * , wxMenuInfoList ) ;
127
128template<> void wxCollectionToVariantArray( wxMenuInfoList const &theList, wxxVariantArray &value)
129{
130 wxListCollectionToVariantArray<wxMenuInfoList::compatibility_iterator>( theList , value ) ;
131}
132
133wxBEGIN_PROPERTIES_TABLE(wxMenuBar)
134 wxPROPERTY_COLLECTION( MenuInfos , wxMenuInfoList , wxMenuInfo* , Append , GetMenuInfos , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
135wxEND_PROPERTIES_TABLE()
136
137wxBEGIN_HANDLERS_TABLE(wxMenuBar)
138wxEND_HANDLERS_TABLE()
139
140wxCONSTRUCTOR_DUMMY( wxMenuBar )
141
142#else
143IMPLEMENT_DYNAMIC_CLASS(wxMenu, wxEvtHandler)
144IMPLEMENT_DYNAMIC_CLASS(wxMenuBar, wxWindow)
145IMPLEMENT_DYNAMIC_CLASS(wxMenuInfo, wxObject)
146#endif
147
148const wxMenuInfoList& wxMenuBar::GetMenuInfos() const
149{
150 wxMenuInfoList* list = const_cast< wxMenuInfoList* >( &m_menuInfos ) ;
151 WX_CLEAR_LIST( wxMenuInfoList , *list ) ;
152 for( size_t i = 0 ; i < GetMenuCount() ; ++i )
153 {
154 wxMenuInfo* info = new wxMenuInfo() ;
155 info->Create( const_cast<wxMenuBar*>(this)->GetMenu(i) , GetMenuLabel(i) ) ;
156 list->Append( info ) ;
157 }
158 return m_menuInfos ;
159}
160
161// ---------------------------------------------------------------------------
162// wxMenu construction, adding and removing menu items
163// ---------------------------------------------------------------------------
164
165// Construct a menu with optional title (then use append)
166void wxMenu::Init()
167{
168}
169
170// The wxWindow destructor will take care of deleting the submenus.
171wxMenu::~wxMenu()
172{
173}
174
175void wxMenu::Break()
176{
177}
178
179void wxMenu::Attach(wxMenuBarBase *menubar)
180{
181 wxMenuBase::Attach(menubar);
182}
183
184#if wxUSE_ACCEL
185
186int wxMenu::FindAccel(int id) const
187{
188 return wxNOT_FOUND;
189}
190
191void wxMenu::UpdateAccel(wxMenuItem *item)
192{
193}
194
195#endif // wxUSE_ACCEL
196
197// append a new item or submenu to the menu
198bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos)
199{
200 if ( IsAttached() && GetMenuBar()->IsAttached() )
201 {
202 // Regenerate the menu resource
203 GetMenuBar()->Refresh();
204 }
205
206 return true;
207}
208
209void wxMenu::EndRadioGroup()
210{
211}
212
213wxMenuItem* wxMenu::DoAppend(wxMenuItem *item)
214{
215 wxCHECK_MSG( item, NULL, _T("NULL item in wxMenu::DoAppend") );
216
217 if(!wxMenuBase::DoAppend(item) || !DoInsertOrAppend(item))
218 {
219 return NULL;
220 }
221 else if(IsAttached() && GetMenuBar()->IsAttached())
222 {
223 // Regenerate the menu resource
224 GetMenuBar()->Refresh();
225 }
226
227 return item;
228}
229
230wxMenuItem* wxMenu::DoInsert(size_t pos, wxMenuItem *item)
231{
232 if (wxMenuBase::DoInsert(pos, item) && DoInsertOrAppend(item, pos))
233 return item;
234 else
235 return NULL;
236}
237
238wxMenuItem *wxMenu::DoRemove(wxMenuItem *item)
239{
240 // we need to find the items position in the child list
241 size_t pos;
242 wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst();
243 for ( pos = 0; node; pos++ )
244 {
245 if ( node->GetData() == item )
246 break;
247
248 node = node->GetNext();
249 }
250
251 // DoRemove() (unlike Remove) can only be called for existing item!
252 wxCHECK_MSG( node, NULL, wxT("bug in wxMenu::Remove logic") );
253
254 // remove the item from the menu
255 wxMenuItem *ret=wxMenuBase::DoRemove(item);
256
257 if ( IsAttached() && GetMenuBar()->IsAttached() )
258 {
259 // Regenerate the menu resource
260 GetMenuBar()->Refresh();
261 }
262
263 return ret;
264}
265
266// ---------------------------------------------------------------------------
267// accelerator helpers
268// ---------------------------------------------------------------------------
269
270#if wxUSE_ACCEL
271
272// create the wxAcceleratorEntries for our accels and put them into provided
273// array - return the number of accels we have
274size_t wxMenu::CopyAccels(wxAcceleratorEntry *accels) const
275{
276 size_t count = GetAccelCount();
277 for ( size_t n = 0; n < count; n++ )
278 {
279 *accels++ = *m_accels[n];
280 }
281
282 return count;
283}
284
285#endif // wxUSE_ACCEL
286
287// ---------------------------------------------------------------------------
288// set wxMenu title
289// ---------------------------------------------------------------------------
290
291void wxMenu::SetTitle(const wxString& label)
292{
293 m_title = label;
294
295 if ( IsAttached() && GetMenuBar()->IsAttached() )
296 {
297 // Regenerate the menu resource
298 GetMenuBar()->Refresh();
299 }
300}
301
302// ---------------------------------------------------------------------------
303// event processing
304// ---------------------------------------------------------------------------
305
306bool wxMenu::PalmCommand(WXUINT WXUNUSED(param), WXWORD id)
307{
308 return false;
309}
310
311// ---------------------------------------------------------------------------
312// other
313// ---------------------------------------------------------------------------
314
315wxWindow *wxMenu::GetWindow() const
316{
317 return NULL;
318}
319
320// ---------------------------------------------------------------------------
321// Menu Bar
322// ---------------------------------------------------------------------------
323
324void wxMenuBar::Init()
325{
326}
327
328wxMenuBar::wxMenuBar()
329{
330}
331
332wxMenuBar::wxMenuBar( long WXUNUSED(style) )
333{
334}
335
336wxMenuBar::wxMenuBar(size_t count, wxMenu *menus[], const wxString titles[], long WXUNUSED(style))
337{
338}
339
340wxMenuBar::~wxMenuBar()
341{
342}
343
344// ---------------------------------------------------------------------------
345// wxMenuBar helpers
346// ---------------------------------------------------------------------------
347
348void wxMenuBar::Refresh()
349{
350 wxCHECK_RET( IsAttached(), wxT("can't refresh unattached menubar") );
351
352 // Regenerate the menu resource
353 LoadMenu();
354}
355
356WXHMENU wxMenuBar::Create()
357{
358 return NULL;
359}
360
361int wxMenuBar::PalmPositionForWxMenu(wxMenu *menu, int wxpos)
362{
363 return -1;
364}
365
366// ---------------------------------------------------------------------------
367// wxMenuBar functions to work with the top level submenus
368// ---------------------------------------------------------------------------
369
370void wxMenuBar::EnableTop(size_t pos, bool enable)
371{
372 // Palm OS does not have support for grayed or disabled items
373}
374
375void wxMenuBar::SetMenuLabel(size_t pos, const wxString& label)
376{
377 wxCHECK_RET( pos < GetMenuCount(), wxT("invalid menu index") );
378
379 m_titles[pos] = label;
380
381 if ( !IsAttached() )
382 {
383 return;
384 }
385
386 // Regenerate the menu resource
387 Refresh();
388}
389
390wxString wxMenuBar::GetMenuLabel(size_t pos) const
391{
392 wxCHECK_MSG( pos < GetMenuCount(), wxEmptyString,
393 wxT("invalid menu index in wxMenuBar::GetMenuLabel") );
394
395 return m_titles[pos];
396}
397
398// ---------------------------------------------------------------------------
399// wxMenuBar construction
400// ---------------------------------------------------------------------------
401
402wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title)
403{
404 wxMenu *menuOld = wxMenuBarBase::Replace(pos, menu, title);
405 if ( !menuOld )
406 return NULL;
407
408 m_titles[pos] = title;
409
410 if ( IsAttached() )
411 {
412 // Regenerate the menu resource
413 Refresh();
414 }
415
416 return menuOld;
417}
418
419bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title)
420{
421 if ( !wxMenuBarBase::Insert(pos, menu, title) )
422 return false;
423
424 m_titles.Insert(title, pos);
425
426 if ( IsAttached() )
427 {
428 // Regenerate the menu resource
429 Refresh();
430 }
431
432 return true;
433}
434
435bool wxMenuBar::Append(wxMenu *menu, const wxString& title)
436{
437 if ( !wxMenuBarBase::Append(menu, title) )
438 return false;
439
440 m_titles.Add(title);
441
442 if(IsAttached())
443 {
444 // Regenerate the menu resource
445 Refresh();
446 }
447
448 return true;
449}
450
451wxMenu *wxMenuBar::Remove(size_t pos)
452{
453 wxMenu *menu = wxMenuBarBase::Remove(pos);
454 if ( !menu )
455 return NULL;
456
457 m_titles.RemoveAt(pos);
458
459 if (IsAttached())
460 {
461 // Regenerate the menu resource
462 Refresh();
463 }
464
465 return menu;
466}
467
468#if wxUSE_ACCEL
469
470void wxMenuBar::RebuildAccelTable()
471{
472}
473
474#endif // wxUSE_ACCEL
475
476int wxMenuBar::ProcessCommand(int ItemID)
477{
478 if(!IsAttached())
479 return -1;
480
481 int MenuNum=(ItemID/1000)-1;
482 int ItemNum=(ItemID-(1000*(MenuNum+1)));
483
484 // Should never happen, but it doesn't hurt to check anyway.
485 if(MenuNum>GetMenuCount())
486 return -1;
487
488 // Get the menu
489 wxMenu *ActiveMenu=GetMenu(MenuNum);
490
491 // Make sure this is a valid item.
492 if(ItemNum>ActiveMenu->GetMenuItemCount())
493 return -1;
494
495 // Get the item
496 wxMenuItem *ActiveItem=ActiveMenu->FindItemByPosition(ItemNum);
497 int ActiveID=ActiveItem->GetId();
498
499 return ActiveID;
500}
501
502/* Palm OS does not have good dynamic menu support. About all you can do with
503 * the standard API calls is to add new items to an existing drop-down menu and
504 * hide/show items in a drop-down menu. It is impossible to add, hide, or
505 * change the label on a drop-down menu.
506 *
507 * The easiest and simplest way around this limitation is to modify the Palm OS
508 * MenuBarType structure directly. This gives limited ability to change the
509 * label on a drop-down menu. I have not been able to find a safe way to add,
510 * delete, or resize drop-down menus in OS 6.
511 *
512 * The following routine attempt to work around these limitations present in the
513 * Palm OS API to provide limited dynamic menu support. This solution is far
514 * from perfect, but the only other option is to wait for PalmSource to add full
515 * dynamic menu support, or to recreate the Palm OS menu system from scratch.
516 *
517 * This system is limited in that no more than 4 drop-down menus are allowed per
518 * menu bar, and the label for each drop-down menu is limited to 8 characters of
519 * text. However, this menu system should work for most applications.
520 *
521 * Basically the menu routines select one of four menu bars, depending on
522 * whether or not the requested menu bar has one, two, three, or four drop-down
523 * menus.
524 *
525 * These four "template" menu bars contain one, two, three, or four drop-down
526 * menus. Each menu has a dummy menu item attached to it to allow the Palm OS
527 * MenuAddItem function to add the real items.
528 *
529 * The labels on the drop-down menus are then replaced with the labels of the
530 * real menus.
531 *
532 * The menu is then attached to the active window and the MenuAddItem API
533 * function is called to add the items to each drop-down menu. Finally,
534 * MenuHideItem is called to remove the dummy items from each drop-down menu.
535 */
536void wxMenuBar::LoadMenu()
537{
538 int i=0;
539 int j=0;
540
541 // Handle to the currently running application database
542 DmOpenRef AppDB;
543
544 // Get app database reference - needed for some Palm OS Menu API calls.
545 SysGetModuleDatabase(SysGetRefNum(), NULL, &AppDB);
546
547 // Get the number of menus
548 int NumMenus=GetMenuCount();
549
550 // Set up the pointers and handles
551 char *PalmOSMenuBarPtr;
552 MemHandle PalmOSMenuBar;
553
554 // Load the menu template and set up the menu pointers
555 if(NumMenus==1)
556 {
557 PalmOSMenuBar=DmGetResource(AppDB,'MBAR',1000);
558 PalmOSMenuBarPtr=(char *)MemHandleLock(PalmOSMenuBar);
559
560 PalmOSMenuBarPtr+=74;
561 }
562 else if(NumMenus==2)
563 {
564 PalmOSMenuBar=DmGetResource(AppDB,'MBAR',2000);
565 PalmOSMenuBarPtr=(char *)MemHandleLock(PalmOSMenuBar);
566
567 PalmOSMenuBarPtr+=116;
568 }
569 else if(NumMenus==3)
570 {
571 PalmOSMenuBar=DmGetResource(AppDB,'MBAR',3000);
572 PalmOSMenuBarPtr=(char *)MemHandleLock(PalmOSMenuBar);
573
574 PalmOSMenuBarPtr+=158;
575 }
576 else
577 {
578 // We support a maximum of 4 menus, so make sure that do not create
579 // more than we can handle.
580 NumMenus=4;
581
582 PalmOSMenuBar=DmGetResource(AppDB,'MBAR',4000);
583 PalmOSMenuBarPtr=(char *)MemHandleLock(PalmOSMenuBar);
584
585 PalmOSMenuBarPtr+=200;
586 }
587
588 // Set the proper names for the drop-down triggers.
589 for(i=0;i<NumMenus;i++)
590 {
591 // Clear out the old label
592 char buffer[8]={' ',' ',' ',' ',' ',' ',' ',' '};
593 MemMove(PalmOSMenuBarPtr,buffer,8);
594
595 wxString MenuTitle=m_titles.Item(i);
596
597 // Make sure we don't copy more than 8 bytes for the label
598 int LengthToCopy=MenuTitle.length();
599 if(LengthToCopy>8)
600 LengthToCopy=8;
601
602 MemMove(PalmOSMenuBarPtr,MenuTitle,LengthToCopy);
603 PalmOSMenuBarPtr+=11;
604 }
605
606 // We are done with the menu pointer.
607 MemHandleUnlock(PalmOSMenuBar);
608 DmReleaseResource(PalmOSMenuBar);
609
610 // We must make the menu active before we can add items to the drop-down
611 // triggers.
612 FrmSetMenu(FrmGetActiveForm(),AppDB,NumMenus*1000);
613
614 /* Add the menu items to the drop-down triggers. This must be done after
615 * setting the triggers, because setting the names of drop-down triggers
616 * that have a variable number of items requires carefull calculation of
617 * the offsets in the MenuBarType structure. Setting the triggers first
618 * avoids this.
619 */
620 for(i=0;i<NumMenus;i++)
621 {
622 wxMenu *CurrentMenu=GetMenu(i);
623
624 for(j=0;j<CurrentMenu->GetMenuItemCount();j++)
625 {
626 wxMenuItem *CurrentItem=CurrentMenu->FindItemByPosition(j);
627 wxString ItemLabel=CurrentItem->GetLabel();
628
629 if(CurrentItem->IsSeparator()==true)
630 {
631 char Separator=MenuSeparatorChar;
632 if(j==0)
633 MenuAddItem(9000+i,((i*1000)+1000)+j,0x00,&Separator);
634 else
635 MenuAddItem(((i*1000)+1000)+j-1,((i*1000)+1000)+j,0x00,&Separator);
636 }
637 else
638 {
639 if(j==0)
640 MenuAddItem(9000+i,((i*1000)+1000)+j,0x00,ItemLabel);
641 else
642 MenuAddItem(((i*1000)+1000)+j-1,((i*1000)+1000)+j,0x00,ItemLabel);
643 }
644 }
645
646 // Hide the dummy menu item, since we don't need it anymore.
647 MenuHideItem(9000+i);
648 }
649}
650
651void wxMenuBar::Attach(wxFrame *frame)
652{
653 // before attaching preprocess menus to not include wxID_EXIT item
654 // as PalmOS guidelines suggest
655
656 wxMenuItem *item;
657 wxMenu *menu;
658 int i;
659
660 while( item = FindItem(wxID_EXIT) )
661 {
662 menu = item->GetMenu();
663 if( !menu ) break; // something broken ?
664
665 size_t count = menu->GetMenuItemCount();
666 if( count == 0 ) break; // something broken ?
667
668 // if EXIT is last item in menu
669 if( menu->FindItemByPosition( count - 1 ) == item )
670 {
671 menu->Destroy( item );
672
673 // was more than one item?
674 // was previous separator ?
675 if( count > 2 )
676 {
677 item = menu->FindItemByPosition( count - 2 );
678 if(item && item->IsSeparator())
679 menu->Destroy( item );
680 }
681 }
682
683 // if EXIT is first item in menu
684 else if( menu->FindItemByPosition( 0 ) == item )
685 {
686 menu->Destroy( item );
687
688 // was more than one item?
689 // was previous separator ?
690 if( count > 2 )
691 {
692 item = menu->FindItemByPosition( 0 );
693 if(item && item->IsSeparator())
694 menu->Destroy( item );
695 }
696 }
697
698 // if EXIT is in the middle but before and after are selectors
699 else
700 {
701 i = 1; // 0 case already done
702 while ( (i < count) && (menu->FindItemByPosition( 0 ) != item) )
703 {
704 i++;
705 }
706
707 if (i >= count) break;
708 if (menu->FindItemByPosition( i ) != item) break;
709 menu->Destroy( item );
710 item = menu->FindItemByPosition( i );
711 if ( item &&
712 item->IsSeparator() &&
713 menu->FindItemByPosition( i-1 )->IsSeparator() )
714 {
715 // noe need for two neighbouring separators
716 menu->Destroy( item );
717 }
718 }
719 }
720
721 // check if we received any empty menu!
722 i = 0;
723 while(i < GetMenuCount())
724 {
725 menu = GetMenu(i);
726
727 if( menu && (menu->GetMenuItemCount()==0) )
728 {
729 menu = Remove( i );
730 delete menu;
731 }
732 else
733 i++;
734 }
735
736 wxMenuBarBase::Attach(frame);
737
738 LoadMenu();
739}
740
741void wxMenuBar::Detach()
742{
743 wxMenuBarBase::Detach();
744}
745
746#endif // wxUSE_MENUS