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