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