PageRenderTime 49ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/ExtLibs/wxWidgets/src/palmos/menu.cpp

https://bitbucket.org/lennonchan/cafu
C++ | 658 lines | 381 code | 132 blank | 145 comment | 64 complexity | 1940de392f9eccd1ee494630370f5c0b MD5 | raw file
  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. // declarations
  13. // ===========================================================================
  14. // ---------------------------------------------------------------------------
  15. // headers
  16. // ---------------------------------------------------------------------------
  17. // For compilers that support precompilation, includes "wx.h".
  18. #include "wx/wxprec.h"
  19. #ifdef __BORLANDC__
  20. #pragma hdrstop
  21. #endif
  22. #if wxUSE_MENUS
  23. #include "wx/menu.h"
  24. #ifndef WX_PRECOMP
  25. #include "wx/frame.h"
  26. #include "wx/utils.h"
  27. #include "wx/intl.h"
  28. #include "wx/log.h"
  29. #endif
  30. #if wxUSE_OWNER_DRAWN
  31. #include "wx/ownerdrw.h"
  32. #endif
  33. #ifdef __WXPALMOS6__
  34. #include <Loader.h>
  35. #else // __WXPALMOS5__
  36. #include <UIResources.h> // MenuRscType
  37. #endif
  38. #include <Form.h>
  39. #include <Menu.h>
  40. // ----------------------------------------------------------------------------
  41. // global variables
  42. // ----------------------------------------------------------------------------
  43. extern wxMenu *wxCurrentPopupMenu;
  44. // ----------------------------------------------------------------------------
  45. // constants
  46. // ----------------------------------------------------------------------------
  47. // the (popup) menu title has this special id
  48. static const int idMenuTitle = -3;
  49. // ----------------------------------------------------------------------------
  50. // private functions
  51. // ----------------------------------------------------------------------------
  52. // ============================================================================
  53. // implementation
  54. // ============================================================================
  55. // ---------------------------------------------------------------------------
  56. // wxMenu construction, adding and removing menu items
  57. // ---------------------------------------------------------------------------
  58. // Construct a menu with optional title (then use append)
  59. void wxMenu::Init()
  60. {
  61. }
  62. // The wxWindow destructor will take care of deleting the submenus.
  63. wxMenu::~wxMenu()
  64. {
  65. }
  66. void wxMenu::Break()
  67. {
  68. }
  69. void wxMenu::Attach(wxMenuBarBase *menubar)
  70. {
  71. wxMenuBase::Attach(menubar);
  72. }
  73. #if wxUSE_ACCEL
  74. int wxMenu::FindAccel(int id) const
  75. {
  76. return wxNOT_FOUND;
  77. }
  78. void wxMenu::UpdateAccel(wxMenuItem *item)
  79. {
  80. }
  81. #endif // wxUSE_ACCEL
  82. // append a new item or submenu to the menu
  83. bool wxMenu::DoInsertOrAppend(wxMenuItem *pItem, size_t pos)
  84. {
  85. if ( IsAttached() && GetMenuBar()->IsAttached() )
  86. {
  87. // Regenerate the menu resource
  88. GetMenuBar()->Refresh();
  89. }
  90. return true;
  91. }
  92. void wxMenu::EndRadioGroup()
  93. {
  94. }
  95. wxMenuItem* wxMenu::DoAppend(wxMenuItem *item)
  96. {
  97. wxCHECK_MSG( item, NULL, wxT("NULL item in wxMenu::DoAppend") );
  98. if(!wxMenuBase::DoAppend(item) || !DoInsertOrAppend(item))
  99. {
  100. return NULL;
  101. }
  102. else if(IsAttached() && GetMenuBar()->IsAttached())
  103. {
  104. // Regenerate the menu resource
  105. GetMenuBar()->Refresh();
  106. }
  107. return item;
  108. }
  109. wxMenuItem* wxMenu::DoInsert(size_t pos, wxMenuItem *item)
  110. {
  111. if (wxMenuBase::DoInsert(pos, item) && DoInsertOrAppend(item, pos))
  112. return item;
  113. else
  114. return NULL;
  115. }
  116. wxMenuItem *wxMenu::DoRemove(wxMenuItem *item)
  117. {
  118. // we need to find the items position in the child list
  119. size_t pos;
  120. wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst();
  121. for ( pos = 0; node; pos++ )
  122. {
  123. if ( node->GetData() == item )
  124. break;
  125. node = node->GetNext();
  126. }
  127. // DoRemove() (unlike Remove) can only be called for existing item!
  128. wxCHECK_MSG( node, NULL, wxT("bug in wxMenu::Remove logic") );
  129. // remove the item from the menu
  130. wxMenuItem *ret=wxMenuBase::DoRemove(item);
  131. if ( IsAttached() && GetMenuBar()->IsAttached() )
  132. {
  133. // Regenerate the menu resource
  134. GetMenuBar()->Refresh();
  135. }
  136. return ret;
  137. }
  138. // ---------------------------------------------------------------------------
  139. // accelerator helpers
  140. // ---------------------------------------------------------------------------
  141. #if wxUSE_ACCEL
  142. // create the wxAcceleratorEntries for our accels and put them into provided
  143. // array - return the number of accels we have
  144. size_t wxMenu::CopyAccels(wxAcceleratorEntry *accels) const
  145. {
  146. size_t count = GetAccelCount();
  147. for ( size_t n = 0; n < count; n++ )
  148. {
  149. *accels++ = *m_accels[n];
  150. }
  151. return count;
  152. }
  153. #endif // wxUSE_ACCEL
  154. // ---------------------------------------------------------------------------
  155. // set wxMenu title
  156. // ---------------------------------------------------------------------------
  157. void wxMenu::SetTitle(const wxString& label)
  158. {
  159. m_title = label;
  160. if ( IsAttached() && GetMenuBar()->IsAttached() )
  161. {
  162. // Regenerate the menu resource
  163. GetMenuBar()->Refresh();
  164. }
  165. }
  166. // ---------------------------------------------------------------------------
  167. // event processing
  168. // ---------------------------------------------------------------------------
  169. bool wxMenu::PalmCommand(WXUINT WXUNUSED(param), WXWORD id)
  170. {
  171. return false;
  172. }
  173. // ---------------------------------------------------------------------------
  174. // other
  175. // ---------------------------------------------------------------------------
  176. wxWindow *wxMenu::GetWindow() const
  177. {
  178. return NULL;
  179. }
  180. // ---------------------------------------------------------------------------
  181. // Menu Bar
  182. // ---------------------------------------------------------------------------
  183. void wxMenuBar::Init()
  184. {
  185. }
  186. wxMenuBar::wxMenuBar()
  187. {
  188. }
  189. wxMenuBar::wxMenuBar( long WXUNUSED(style) )
  190. {
  191. }
  192. wxMenuBar::wxMenuBar(size_t count, wxMenu *menus[], const wxString titles[], long WXUNUSED(style))
  193. {
  194. }
  195. wxMenuBar::~wxMenuBar()
  196. {
  197. }
  198. // ---------------------------------------------------------------------------
  199. // wxMenuBar helpers
  200. // ---------------------------------------------------------------------------
  201. void wxMenuBar::Refresh()
  202. {
  203. wxCHECK_RET( IsAttached(), wxT("can't refresh unattached menubar") );
  204. // Regenerate the menu resource
  205. LoadMenu();
  206. }
  207. WXHMENU wxMenuBar::Create()
  208. {
  209. return NULL;
  210. }
  211. int wxMenuBar::PalmPositionForWxMenu(wxMenu *menu, int wxpos)
  212. {
  213. return -1;
  214. }
  215. // ---------------------------------------------------------------------------
  216. // wxMenuBar functions to work with the top level submenus
  217. // ---------------------------------------------------------------------------
  218. void wxMenuBar::EnableTop(size_t pos, bool enable)
  219. {
  220. // Palm OS does not have support for grayed or disabled items
  221. }
  222. void wxMenuBar::SetMenuLabel(size_t pos, const wxString& label)
  223. {
  224. wxCHECK_RET( pos < GetMenuCount(), wxT("invalid menu index") );
  225. m_titles[pos] = label;
  226. if ( !IsAttached() )
  227. {
  228. return;
  229. }
  230. // Regenerate the menu resource
  231. Refresh();
  232. }
  233. wxString wxMenuBar::GetMenuLabel(size_t pos) const
  234. {
  235. wxCHECK_MSG( pos < GetMenuCount(), wxEmptyString,
  236. wxT("invalid menu index in wxMenuBar::GetMenuLabel") );
  237. return m_titles[pos];
  238. }
  239. // ---------------------------------------------------------------------------
  240. // wxMenuBar construction
  241. // ---------------------------------------------------------------------------
  242. wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title)
  243. {
  244. wxMenu *menuOld = wxMenuBarBase::Replace(pos, menu, title);
  245. if ( !menuOld )
  246. return NULL;
  247. m_titles[pos] = title;
  248. if ( IsAttached() )
  249. {
  250. // Regenerate the menu resource
  251. Refresh();
  252. }
  253. return menuOld;
  254. }
  255. bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title)
  256. {
  257. if ( !wxMenuBarBase::Insert(pos, menu, title) )
  258. return false;
  259. m_titles.Insert(title, pos);
  260. if ( IsAttached() )
  261. {
  262. // Regenerate the menu resource
  263. Refresh();
  264. }
  265. return true;
  266. }
  267. bool wxMenuBar::Append(wxMenu *menu, const wxString& title)
  268. {
  269. if ( !wxMenuBarBase::Append(menu, title) )
  270. return false;
  271. m_titles.Add(title);
  272. if(IsAttached())
  273. {
  274. // Regenerate the menu resource
  275. Refresh();
  276. }
  277. return true;
  278. }
  279. wxMenu *wxMenuBar::Remove(size_t pos)
  280. {
  281. wxMenu *menu = wxMenuBarBase::Remove(pos);
  282. if ( !menu )
  283. return NULL;
  284. m_titles.RemoveAt(pos);
  285. if (IsAttached())
  286. {
  287. // Regenerate the menu resource
  288. Refresh();
  289. }
  290. return menu;
  291. }
  292. #if wxUSE_ACCEL
  293. void wxMenuBar::RebuildAccelTable()
  294. {
  295. }
  296. #endif // wxUSE_ACCEL
  297. int wxMenuBar::ProcessCommand(int ItemID)
  298. {
  299. if(!IsAttached())
  300. return -1;
  301. int MenuNum=(ItemID/1000)-1;
  302. int ItemNum=(ItemID-(1000*(MenuNum+1)));
  303. // Should never happen, but it doesn't hurt to check anyway.
  304. if(MenuNum>GetMenuCount())
  305. return -1;
  306. // Get the menu
  307. wxMenu *ActiveMenu=GetMenu(MenuNum);
  308. // Make sure this is a valid item.
  309. if(ItemNum>ActiveMenu->GetMenuItemCount())
  310. return -1;
  311. // Get the item
  312. wxMenuItem *ActiveItem=ActiveMenu->FindItemByPosition(ItemNum);
  313. int ActiveID=ActiveItem->GetId();
  314. return ActiveID;
  315. }
  316. /* Palm OS does not have good dynamic menu support. About all you can do with
  317. * the standard API calls is to add new items to an existing drop-down menu and
  318. * hide/show items in a drop-down menu. It is impossible to add, hide, or
  319. * change the label on a drop-down menu.
  320. *
  321. * The easiest and simplest way around this limitation is to modify the Palm OS
  322. * MenuBarType structure directly. This gives limited ability to change the
  323. * label on a drop-down menu. I have not been able to find a safe way to add,
  324. * delete, or resize drop-down menus in OS 6.
  325. *
  326. * The following routine attempt to work around these limitations present in the
  327. * Palm OS API to provide limited dynamic menu support. This solution is far
  328. * from perfect, but the only other option is to wait for PalmSource to add full
  329. * dynamic menu support, or to recreate the Palm OS menu system from scratch.
  330. *
  331. * This system is limited in that no more than 4 drop-down menus are allowed per
  332. * menu bar, and the label for each drop-down menu is limited to 8 characters of
  333. * text. However, this menu system should work for most applications.
  334. *
  335. * Basically the menu routines select one of four menu bars, depending on
  336. * whether or not the requested menu bar has one, two, three, or four drop-down
  337. * menus.
  338. *
  339. * These four "template" menu bars contain one, two, three, or four drop-down
  340. * menus. Each menu has a dummy menu item attached to it to allow the Palm OS
  341. * MenuAddItem function to add the real items.
  342. *
  343. * The labels on the drop-down menus are then replaced with the labels of the
  344. * real menus.
  345. *
  346. * The menu is then attached to the active window and the MenuAddItem API
  347. * function is called to add the items to each drop-down menu. Finally,
  348. * MenuHideItem is called to remove the dummy items from each drop-down menu.
  349. */
  350. void wxMenuBar::LoadMenu()
  351. {
  352. int i=0;
  353. int j=0;
  354. #ifdef __WXPALMOS6__
  355. // Handle to the currently running application database
  356. DmOpenRef AppDB;
  357. // Get app database reference - needed for some Palm OS Menu API calls.
  358. SysGetModuleDatabase(SysGetRefNum(), NULL, &AppDB);
  359. #endif // __WXPALMOS6__
  360. // Get the number of menus
  361. int NumMenus=GetMenuCount();
  362. // Set up the pointers and handles
  363. char *PalmOSMenuBarPtr;
  364. MemHandle PalmOSMenuBar;
  365. // Load the menu template and set up the menu pointers
  366. if(NumMenus==1)
  367. {
  368. PalmOSMenuBar = POS_DmGetResource (AppDB, MenuRscType, 1000);
  369. PalmOSMenuBarPtr = (char *)MemHandleLock (PalmOSMenuBar);
  370. PalmOSMenuBarPtr += 74;
  371. }
  372. else if(NumMenus==2)
  373. {
  374. PalmOSMenuBar = POS_DmGetResource (AppDB, MenuRscType, 2000);
  375. PalmOSMenuBarPtr = (char *)MemHandleLock (PalmOSMenuBar);
  376. PalmOSMenuBarPtr += 116;
  377. }
  378. else if(NumMenus==3)
  379. {
  380. PalmOSMenuBar = POS_DmGetResource (AppDB, MenuRscType, 3000);
  381. PalmOSMenuBarPtr = (char *)MemHandleLock (PalmOSMenuBar);
  382. PalmOSMenuBarPtr += 158;
  383. }
  384. else
  385. {
  386. // We support a maximum of 4 menus, so make sure that do not create
  387. // more than we can handle.
  388. NumMenus=4;
  389. PalmOSMenuBar = POS_DmGetResource (AppDB, MenuRscType, 4000);
  390. PalmOSMenuBarPtr = (char *)MemHandleLock (PalmOSMenuBar);
  391. PalmOSMenuBarPtr += 200;
  392. }
  393. // Set the proper names for the drop-down triggers.
  394. for(i=0;i<NumMenus;i++)
  395. {
  396. // Clear out the old label
  397. char buffer[8]={' ',' ',' ',' ',' ',' ',' ',' '};
  398. MemMove(PalmOSMenuBarPtr,buffer,8);
  399. wxString MenuTitle=m_titles.Item(i);
  400. // Make sure we don't copy more than 8 bytes for the label
  401. int LengthToCopy = MenuTitle.length();
  402. if(LengthToCopy > 8)
  403. LengthToCopy = 8;
  404. MemMove(PalmOSMenuBarPtr,(char*)(&MenuTitle),LengthToCopy);
  405. PalmOSMenuBarPtr+=11;
  406. }
  407. // We are done with the menu pointer.
  408. MemHandleUnlock(PalmOSMenuBar);
  409. DmReleaseResource(PalmOSMenuBar);
  410. // We must make the menu active before we can add items to the drop-down
  411. // triggers.
  412. POS_FrmSetMenu (FrmGetActiveForm(), AppDB, NumMenus * 1000);
  413. /* Add the menu items to the drop-down triggers. This must be done after
  414. * setting the triggers, because setting the names of drop-down triggers
  415. * that have a variable number of items requires carefull calculation of
  416. * the offsets in the MenuBarType structure. Setting the triggers first
  417. * avoids this.
  418. */
  419. for(i=0;i<NumMenus;i++)
  420. {
  421. wxMenu *CurrentMenu=GetMenu(i);
  422. for(j=0;j<CurrentMenu->GetMenuItemCount();j++)
  423. {
  424. wxMenuItem *CurrentItem=CurrentMenu->FindItemByPosition(j);
  425. wxString ItemLabel=CurrentItem->GetLabel();
  426. if(CurrentItem->IsSeparator()==true)
  427. {
  428. char Separator=MenuSeparatorChar;
  429. if(j==0)
  430. MenuAddItem(9000+i,((i*1000)+1000)+j,0x00,&Separator);
  431. else
  432. MenuAddItem(((i*1000)+1000)+j-1,((i*1000)+1000)+j,0x00,&Separator);
  433. }
  434. else
  435. {
  436. if(j==0)
  437. MenuAddItem(9000+i,((i*1000)+1000)+j,0x00,(char *)(&ItemLabel));
  438. else
  439. MenuAddItem(((i*1000)+1000)+j-1,((i*1000)+1000)+j,0x00,(char *)(&ItemLabel));
  440. }
  441. }
  442. // Hide the dummy menu item, since we don't need it anymore.
  443. MenuHideItem(9000+i);
  444. }
  445. }
  446. void wxMenuBar::Attach(wxFrame *frame)
  447. {
  448. // before attaching preprocess menus to not include wxID_EXIT item
  449. // as PalmOS guidelines suggest
  450. wxMenuItem *item;
  451. wxMenu *menu;
  452. int i;
  453. while( item = FindItem(wxID_EXIT) )
  454. {
  455. menu = item->GetMenu();
  456. if( !menu ) break; // something broken ?
  457. size_t count = menu->GetMenuItemCount();
  458. if( count == 0 ) break; // something broken ?
  459. // if EXIT is last item in menu
  460. if( menu->FindItemByPosition( count - 1 ) == item )
  461. {
  462. menu->Destroy( item );
  463. // was more than one item?
  464. // was previous separator ?
  465. if( count > 2 )
  466. {
  467. item = menu->FindItemByPosition( count - 2 );
  468. if(item && item->IsSeparator())
  469. menu->Destroy( item );
  470. }
  471. }
  472. // if EXIT is first item in menu
  473. else if( menu->FindItemByPosition( 0 ) == item )
  474. {
  475. menu->Destroy( item );
  476. // was more than one item?
  477. // was previous separator ?
  478. if( count > 2 )
  479. {
  480. item = menu->FindItemByPosition( 0 );
  481. if(item && item->IsSeparator())
  482. menu->Destroy( item );
  483. }
  484. }
  485. // if EXIT is in the middle but before and after are selectors
  486. else
  487. {
  488. i = 1; // 0 case already done
  489. while ( (i < count) && (menu->FindItemByPosition( 0 ) != item) )
  490. {
  491. i++;
  492. }
  493. if (i >= count) break;
  494. if (menu->FindItemByPosition( i ) != item) break;
  495. menu->Destroy( item );
  496. item = menu->FindItemByPosition( i );
  497. if ( item &&
  498. item->IsSeparator() &&
  499. menu->FindItemByPosition( i-1 )->IsSeparator() )
  500. {
  501. // noe need for two neighbouring separators
  502. menu->Destroy( item );
  503. }
  504. }
  505. }
  506. // check if we received any empty menu!
  507. i = 0;
  508. while(i < GetMenuCount())
  509. {
  510. menu = GetMenu(i);
  511. if( menu && (menu->GetMenuItemCount()==0) )
  512. {
  513. menu = Remove( i );
  514. delete menu;
  515. }
  516. else
  517. i++;
  518. }
  519. wxMenuBarBase::Attach(frame);
  520. LoadMenu();
  521. }
  522. void wxMenuBar::Detach()
  523. {
  524. wxMenuBarBase::Detach();
  525. }
  526. #endif // wxUSE_MENUS