PageRenderTime 72ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/ExtLibs/wxWidgets/src/motif/menu.cpp

https://bitbucket.org/lennonchan/cafu
C++ | 727 lines | 542 code | 118 blank | 67 comment | 93 complexity | f23754b82b468377b361982569d1ab57 MD5 | raw file
  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name: src/motif/menu.cpp
  3. // Purpose: wxMenu, wxMenuBar, wxMenuItem
  4. // Author: Julian Smart
  5. // Modified by:
  6. // Created: 17/09/98
  7. // RCS-ID: $Id$
  8. // Copyright: (c) Julian Smart
  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. #include "wx/menu.h"
  20. #ifndef WX_PRECOMP
  21. #include "wx/log.h"
  22. #include "wx/app.h"
  23. #include "wx/utils.h"
  24. #include "wx/frame.h"
  25. #include "wx/settings.h"
  26. #include "wx/menuitem.h"
  27. #endif
  28. #ifdef __VMS__
  29. #pragma message disable nosimpint
  30. #endif
  31. #include <Xm/Label.h>
  32. #include <Xm/LabelG.h>
  33. #include <Xm/CascadeBG.h>
  34. #include <Xm/CascadeB.h>
  35. #include <Xm/SeparatoG.h>
  36. #include <Xm/PushBG.h>
  37. #include <Xm/ToggleB.h>
  38. #include <Xm/ToggleBG.h>
  39. #include <Xm/RowColumn.h>
  40. #ifdef __VMS__
  41. #pragma message enable nosimpint
  42. #endif
  43. #include "wx/motif/private.h"
  44. // other standard headers
  45. #include <string.h>
  46. // ============================================================================
  47. // implementation
  48. // ============================================================================
  49. // ----------------------------------------------------------------------------
  50. // Menus
  51. // ----------------------------------------------------------------------------
  52. // Construct a menu with optional title (then use append)
  53. void wxMenu::Init()
  54. {
  55. // Motif-specific members
  56. m_numColumns = 1;
  57. m_menuWidget = (WXWidget) NULL;
  58. m_popupShell = (WXWidget) NULL;
  59. m_buttonWidget = (WXWidget) NULL;
  60. m_menuId = 0;
  61. m_topLevelMenu = NULL;
  62. m_ownedByMenuBar = false;
  63. if ( !m_title.empty() )
  64. {
  65. Append(-3, m_title) ;
  66. AppendSeparator() ;
  67. }
  68. }
  69. // The wxWindow destructor will take care of deleting the submenus.
  70. wxMenu::~wxMenu()
  71. {
  72. if (m_menuWidget)
  73. {
  74. if (m_menuParent)
  75. DestroyMenu(true);
  76. else
  77. DestroyMenu(false);
  78. }
  79. // Not sure if this is right
  80. if (m_menuParent && m_menuBar)
  81. {
  82. m_menuParent = NULL;
  83. // m_menuBar = NULL;
  84. }
  85. }
  86. void wxMenu::Break()
  87. {
  88. m_numColumns++;
  89. }
  90. // function appends a new item or submenu to the menu
  91. wxMenuItem* wxMenu::DoAppend(wxMenuItem *pItem)
  92. {
  93. return DoInsert(GetMenuItemCount(), pItem);
  94. }
  95. wxMenuItem *wxMenu::DoRemove(wxMenuItem *item)
  96. {
  97. item->DestroyItem(true);
  98. return wxMenuBase::DoRemove(item);
  99. }
  100. wxMenuItem* wxMenu::DoInsert(size_t pos, wxMenuItem *item)
  101. {
  102. if (m_menuWidget)
  103. {
  104. // this is a dynamic Append
  105. #ifndef XmNpositionIndex
  106. wxCHECK_MSG( pos == GetMenuItemCount(), -1, wxT("insert not implemented"));
  107. #endif
  108. item->CreateItem(m_menuWidget, GetMenuBar(), m_topLevelMenu, pos);
  109. }
  110. if ( item->IsSubMenu() )
  111. {
  112. item->GetSubMenu()->m_topLevelMenu = m_topLevelMenu;
  113. }
  114. return pos == GetMenuItemCount() ? wxMenuBase::DoAppend(item) :
  115. wxMenuBase::DoInsert(pos, item);
  116. }
  117. void wxMenu::SetTitle(const wxString& label)
  118. {
  119. m_title = label;
  120. wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst();
  121. if ( !node )
  122. return;
  123. wxMenuItem *item = node->GetData ();
  124. Widget widget = (Widget) item->GetButtonWidget();
  125. if ( !widget )
  126. return;
  127. wxXmString title_str(label);
  128. XtVaSetValues(widget,
  129. XmNlabelString, title_str(),
  130. NULL);
  131. }
  132. bool wxMenu::ProcessCommand(wxCommandEvent & event)
  133. {
  134. // Try the menu's event handler first
  135. wxEvtHandler * const handler = GetEventHandler();
  136. bool processed = handler ? handler->SafelyProcessEvent(event) : false;
  137. // Try the window the menu was popped up from (and up
  138. // through the hierarchy)
  139. if ( !processed && GetInvokingWindow())
  140. processed = GetInvokingWindow()->HandleWindowEvent(event);
  141. return processed;
  142. }
  143. // ----------------------------------------------------------------------------
  144. // Menu Bar
  145. // ----------------------------------------------------------------------------
  146. void wxMenuBar::Init()
  147. {
  148. m_eventHandler = this;
  149. m_menuBarFrame = NULL;
  150. m_mainWidget = (WXWidget) NULL;
  151. }
  152. wxMenuBar::wxMenuBar(size_t n, wxMenu *menus[], const wxArrayString& titles, long WXUNUSED(style))
  153. {
  154. wxASSERT( n == titles.GetCount() );
  155. Init();
  156. m_titles = titles;
  157. for ( size_t i = 0; i < n; i++ )
  158. m_menus.Append(menus[i]);
  159. }
  160. wxMenuBar::wxMenuBar(size_t n, wxMenu *menus[], const wxString titles[], long WXUNUSED(style))
  161. {
  162. Init();
  163. for ( size_t i = 0; i < n; i++ )
  164. {
  165. m_menus.Append(menus[i]);
  166. m_titles.Add(titles[i]);
  167. }
  168. }
  169. wxMenuBar::~wxMenuBar()
  170. {
  171. // nothing to do: wxMenuBarBase will delete the menus
  172. }
  173. void wxMenuBar::EnableTop(size_t WXUNUSED(pos), bool WXUNUSED(flag))
  174. {
  175. // wxFAIL_MSG("TODO");
  176. // wxLogWarning("wxMenuBar::EnableTop not yet implemented.");
  177. }
  178. void wxMenuBar::SetMenuLabel(size_t pos, const wxString& label)
  179. {
  180. wxMenu *menu = GetMenu(pos);
  181. if ( !menu )
  182. return;
  183. Widget w = (Widget)menu->GetButtonWidget();
  184. if (w)
  185. {
  186. wxXmString label_str(label);
  187. XtVaSetValues(w,
  188. XmNlabelString, label_str(),
  189. NULL);
  190. }
  191. m_titles[pos] = label;
  192. }
  193. wxString wxMenuBar::GetMenuLabel(size_t pos) const
  194. {
  195. wxCHECK_MSG( pos < GetMenuCount(), wxEmptyString,
  196. wxT("invalid menu index in wxMenuBar::GetMenuLabel") );
  197. return m_titles[pos];
  198. }
  199. bool wxMenuBar::Append(wxMenu * menu, const wxString& title)
  200. {
  201. return Insert(GetMenuCount(), menu, title);
  202. }
  203. bool wxMenuBar::Insert(size_t pos, wxMenu *menu, const wxString& title)
  204. {
  205. wxCHECK_MSG( pos <= GetMenuCount(), false, wxT("invalid position") );
  206. wxCHECK_MSG( menu, false, wxT("invalid menu") );
  207. wxCHECK_MSG( !menu->GetParent() && !menu->GetButtonWidget(), false,
  208. wxT("menu already appended") );
  209. if ( m_menuBarFrame )
  210. {
  211. WXWidget w = menu->CreateMenu(this, GetMainWidget(), menu,
  212. pos, title, true);
  213. wxCHECK_MSG( w, false, wxT("failed to create menu") );
  214. menu->SetButtonWidget(w);
  215. }
  216. m_titles.Insert(title, pos);
  217. return wxMenuBarBase::Insert(pos, menu, title);
  218. }
  219. wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title)
  220. {
  221. if ( !wxMenuBarBase::Replace(pos, menu, title) )
  222. return NULL;
  223. wxFAIL_MSG(wxT("TODO"));
  224. return NULL;
  225. }
  226. wxMenu *wxMenuBar::Remove(size_t pos)
  227. {
  228. wxMenu *menu = wxMenuBarBase::Remove(pos);
  229. if ( !menu )
  230. return NULL;
  231. if ( m_menuBarFrame )
  232. menu->DestroyMenu(true);
  233. menu->SetMenuBar(NULL);
  234. m_titles.RemoveAt(pos);
  235. return menu;
  236. }
  237. // Find the menu menuString, item itemString, and return the item id.
  238. // Returns -1 if none found.
  239. int wxMenuBar::FindMenuItem(const wxString& menuString, const wxString& itemString) const
  240. {
  241. const wxString stripped = wxStripMenuCodes(menuString);
  242. size_t menuCount = GetMenuCount();
  243. for (size_t i = 0; i < menuCount; i++)
  244. {
  245. if ( wxStripMenuCodes(m_titles[i]) == stripped )
  246. return m_menus.Item(i)->GetData()->FindItem (itemString);
  247. }
  248. return wxNOT_FOUND;
  249. }
  250. wxMenuItem *wxMenuBar::FindItem(int id, wxMenu ** itemMenu) const
  251. {
  252. if (itemMenu)
  253. *itemMenu = NULL;
  254. size_t menuCount = GetMenuCount();
  255. for (size_t i = 0; i < menuCount; i++)
  256. {
  257. wxMenuItem *item = m_menus.Item(i)->GetData()->FindItem(id, itemMenu);
  258. if (item) return item;
  259. }
  260. return NULL;
  261. }
  262. // Create menubar
  263. bool wxMenuBar::CreateMenuBar(wxFrame* parent)
  264. {
  265. m_parent = parent; // bleach... override it!
  266. PreCreation();
  267. m_parent = NULL;
  268. if (m_mainWidget)
  269. {
  270. XtVaSetValues((Widget) parent->GetMainWidget(), XmNmenuBar, (Widget) m_mainWidget, NULL);
  271. /*
  272. if (!XtIsManaged((Widget) m_mainWidget))
  273. XtManageChild((Widget) m_mainWidget);
  274. */
  275. XtMapWidget((Widget) m_mainWidget);
  276. return true;
  277. }
  278. Widget menuBarW = XmCreateMenuBar ((Widget) parent->GetMainWidget(),
  279. wxMOTIF_STR("MenuBar"), NULL, 0);
  280. m_mainWidget = (WXWidget) menuBarW;
  281. size_t menuCount = GetMenuCount();
  282. for (size_t i = 0; i < menuCount; i++)
  283. {
  284. wxMenu *menu = GetMenu(i);
  285. wxString title(m_titles[i]);
  286. menu->SetButtonWidget(menu->CreateMenu (this, menuBarW, menu, i, title, true));
  287. if (strcmp (wxStripMenuCodes(title), "Help") == 0)
  288. XtVaSetValues ((Widget) menuBarW, XmNmenuHelpWidget, (Widget) menu->GetButtonWidget(), NULL);
  289. // tear off menu support
  290. #if (XmVersion >= 1002)
  291. if ( menu->IsTearOff() )
  292. {
  293. XtVaSetValues(GetWidget(menu),
  294. XmNtearOffModel, XmTEAR_OFF_ENABLED,
  295. NULL);
  296. Widget tearOff = XmGetTearOffControl(GetWidget(menu));
  297. wxDoChangeForegroundColour((Widget) tearOff, m_foregroundColour);
  298. wxDoChangeBackgroundColour((Widget) tearOff, m_backgroundColour, true);
  299. }
  300. #endif
  301. }
  302. PostCreation();
  303. XtVaSetValues((Widget) parent->GetMainWidget(), XmNmenuBar, (Widget) m_mainWidget, NULL);
  304. XtRealizeWidget ((Widget) menuBarW);
  305. XtManageChild ((Widget) menuBarW);
  306. SetMenuBarFrame(parent);
  307. return true;
  308. }
  309. // Destroy menubar, but keep data structures intact so we can recreate it.
  310. bool wxMenuBar::DestroyMenuBar()
  311. {
  312. if (!m_mainWidget)
  313. {
  314. SetMenuBarFrame(NULL);
  315. return false;
  316. }
  317. XtUnmanageChild ((Widget) m_mainWidget);
  318. XtUnrealizeWidget ((Widget) m_mainWidget);
  319. size_t menuCount = GetMenuCount();
  320. for (size_t i = 0; i < menuCount; i++)
  321. {
  322. wxMenu *menu = GetMenu(i);
  323. menu->DestroyMenu(true);
  324. }
  325. XtDestroyWidget((Widget) m_mainWidget);
  326. m_mainWidget = (WXWidget) 0;
  327. SetMenuBarFrame(NULL);
  328. return true;
  329. }
  330. // Since PopupMenu under Motif stills grab right mouse button events
  331. // after it was closed, we need to delete the associated widgets to
  332. // allow next PopUpMenu to appear...
  333. void wxMenu::DestroyWidgetAndDetach()
  334. {
  335. if (GetMainWidget())
  336. {
  337. wxMenu *menuParent = GetParent();
  338. if ( menuParent )
  339. {
  340. wxMenuItemList::compatibility_iterator node = menuParent->GetMenuItems().GetFirst();
  341. while ( node )
  342. {
  343. if ( node->GetData()->GetSubMenu() == this )
  344. {
  345. delete node->GetData();
  346. menuParent->GetMenuItems().Erase(node);
  347. break;
  348. }
  349. node = node->GetNext();
  350. }
  351. }
  352. DestroyMenu(true);
  353. }
  354. // Mark as no longer popped up
  355. m_menuId = -1;
  356. }
  357. /*
  358. * Create a popup or pulldown menu.
  359. * Submenus of a popup will be pulldown.
  360. *
  361. */
  362. WXWidget wxMenu::CreateMenu (wxMenuBar * menuBar,
  363. WXWidget parent,
  364. wxMenu * topMenu,
  365. size_t menuIndex,
  366. const wxString& title,
  367. bool pullDown)
  368. {
  369. Widget menu = (Widget) 0;
  370. Widget buttonWidget = (Widget) 0;
  371. Display* dpy = XtDisplay((Widget)parent);
  372. Arg args[5];
  373. XtSetArg (args[0], XmNnumColumns, m_numColumns);
  374. XtSetArg (args[1], XmNpacking, (m_numColumns > 1) ? XmPACK_COLUMN : XmPACK_TIGHT);
  375. if ( !m_font.IsOk() )
  376. {
  377. if ( menuBar )
  378. m_font = menuBar->GetFont();
  379. else if ( GetInvokingWindow() )
  380. m_font = GetInvokingWindow()->GetFont();
  381. }
  382. XtSetArg (args[2], (String)wxFont::GetFontTag(), m_font.GetFontTypeC(dpy) );
  383. if (!pullDown)
  384. {
  385. menu = XmCreatePopupMenu ((Widget) parent, wxMOTIF_STR("popup"), args, 3);
  386. #if 0
  387. XtAddCallback(menu,
  388. XmNunmapCallback,
  389. (XtCallbackProc)wxMenuPopdownCallback,
  390. (XtPointer)this);
  391. #endif
  392. }
  393. else
  394. {
  395. char mnem = wxFindMnemonic (title);
  396. menu = XmCreatePulldownMenu ((Widget) parent, wxMOTIF_STR("pulldown"), args, 3);
  397. wxString title2(wxStripMenuCodes(title));
  398. wxXmString label_str(title2);
  399. buttonWidget = XtVaCreateManagedWidget(title2,
  400. #if wxUSE_GADGETS
  401. xmCascadeButtonGadgetClass, (Widget) parent,
  402. #else
  403. xmCascadeButtonWidgetClass, (Widget) parent,
  404. #endif
  405. XmNlabelString, label_str(),
  406. XmNsubMenuId, menu,
  407. (String)wxFont::GetFontTag(), m_font.GetFontTypeC(dpy),
  408. XmNpositionIndex, menuIndex,
  409. NULL);
  410. if (mnem != 0)
  411. XtVaSetValues (buttonWidget, XmNmnemonic, mnem, NULL);
  412. }
  413. m_menuWidget = (WXWidget) menu;
  414. m_topLevelMenu = topMenu;
  415. size_t i = 0;
  416. for ( wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst();
  417. node;
  418. node = node->GetNext(), ++i )
  419. {
  420. wxMenuItem *item = node->GetData();
  421. item->CreateItem(menu, menuBar, topMenu, i);
  422. }
  423. ChangeFont();
  424. return buttonWidget;
  425. }
  426. // Destroys the Motif implementation of the menu,
  427. // but maintains the wxWidgets data structures so we can
  428. // do a CreateMenu again.
  429. void wxMenu::DestroyMenu (bool full)
  430. {
  431. for ( wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst();
  432. node;
  433. node = node->GetNext() )
  434. {
  435. wxMenuItem *item = node->GetData();
  436. item->SetMenuBar(NULL);
  437. item->DestroyItem(full);
  438. }
  439. if (m_buttonWidget)
  440. {
  441. if (full)
  442. {
  443. XtVaSetValues((Widget) m_buttonWidget, XmNsubMenuId, NULL, NULL);
  444. XtDestroyWidget ((Widget) m_buttonWidget);
  445. m_buttonWidget = (WXWidget) 0;
  446. }
  447. }
  448. if (m_menuWidget && full)
  449. {
  450. XtDestroyWidget((Widget) m_menuWidget);
  451. m_menuWidget = (WXWidget) NULL;
  452. }
  453. }
  454. WXWidget wxMenu::FindMenuItem (int id, wxMenuItem ** it) const
  455. {
  456. if (id == m_menuId)
  457. {
  458. if (it)
  459. *it = NULL;
  460. return m_buttonWidget;
  461. }
  462. for ( wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst();
  463. node;
  464. node = node->GetNext() )
  465. {
  466. wxMenuItem *item = node->GetData ();
  467. if (item->GetId() == id)
  468. {
  469. if (it)
  470. *it = item;
  471. return item->GetButtonWidget();
  472. }
  473. if (item->GetSubMenu())
  474. {
  475. WXWidget w = item->GetSubMenu()->FindMenuItem (id, it);
  476. if (w)
  477. {
  478. return w;
  479. }
  480. }
  481. }
  482. if (it)
  483. *it = NULL;
  484. return (WXWidget) NULL;
  485. }
  486. void wxMenu::SetBackgroundColour(const wxColour& col)
  487. {
  488. m_backgroundColour = col;
  489. if (!col.IsOk())
  490. return;
  491. if (m_menuWidget)
  492. wxDoChangeBackgroundColour(m_menuWidget, (wxColour&) col);
  493. if (m_buttonWidget)
  494. wxDoChangeBackgroundColour(m_buttonWidget, (wxColour&) col, true);
  495. for ( wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst();
  496. node;
  497. node = node->GetNext() )
  498. {
  499. wxMenuItem* item = node->GetData();
  500. if (item->GetButtonWidget())
  501. {
  502. // This crashes because it uses gadgets
  503. // wxDoChangeBackgroundColour(item->GetButtonWidget(), (wxColour&) col, true);
  504. }
  505. if (item->GetSubMenu())
  506. item->GetSubMenu()->SetBackgroundColour((wxColour&) col);
  507. }
  508. }
  509. void wxMenu::SetForegroundColour(const wxColour& col)
  510. {
  511. m_foregroundColour = col;
  512. if (!col.IsOk())
  513. return;
  514. if (m_menuWidget)
  515. wxDoChangeForegroundColour(m_menuWidget, (wxColour&) col);
  516. if (m_buttonWidget)
  517. wxDoChangeForegroundColour(m_buttonWidget, (wxColour&) col);
  518. for ( wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst();
  519. node;
  520. node = node->GetNext() )
  521. {
  522. wxMenuItem* item = node->GetData();
  523. if (item->GetButtonWidget())
  524. {
  525. // This crashes because it uses gadgets
  526. // wxDoChangeForegroundColour(item->GetButtonWidget(), (wxColour&) col);
  527. }
  528. if (item->GetSubMenu())
  529. item->GetSubMenu()->SetForegroundColour((wxColour&) col);
  530. }
  531. }
  532. void wxMenu::ChangeFont(bool keepOriginalSize)
  533. {
  534. // Lesstif 0.87 hangs here, but 0.93 does not; MBN: sometimes it does
  535. #if !wxCHECK_LESSTIF() // || wxCHECK_LESSTIF_VERSION( 0, 93 )
  536. if (!m_font.IsOk() || !m_menuWidget)
  537. return;
  538. Display* dpy = XtDisplay((Widget) m_menuWidget);
  539. XtVaSetValues ((Widget) m_menuWidget,
  540. wxFont::GetFontTag(), m_font.GetFontTypeC(dpy),
  541. NULL);
  542. if (m_buttonWidget)
  543. {
  544. XtVaSetValues ((Widget) m_buttonWidget,
  545. wxFont::GetFontTag(), m_font.GetFontTypeC(dpy),
  546. NULL);
  547. }
  548. for ( wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst();
  549. node;
  550. node = node->GetNext() )
  551. {
  552. wxMenuItem* item = node->GetData();
  553. if (m_menuWidget && item->GetButtonWidget() && m_font.IsOk())
  554. {
  555. XtVaSetValues ((Widget) item->GetButtonWidget(),
  556. wxFont::GetFontTag(), m_font.GetFontTypeC(dpy),
  557. NULL);
  558. }
  559. if (item->GetSubMenu())
  560. item->GetSubMenu()->ChangeFont(keepOriginalSize);
  561. }
  562. #else
  563. wxUnusedVar(keepOriginalSize);
  564. #endif
  565. }
  566. void wxMenu::SetFont(const wxFont& font)
  567. {
  568. m_font = font;
  569. ChangeFont();
  570. }
  571. bool wxMenuBar::SetBackgroundColour(const wxColour& col)
  572. {
  573. if (!wxWindowBase::SetBackgroundColour(col))
  574. return false;
  575. if (!col.IsOk())
  576. return false;
  577. if (m_mainWidget)
  578. wxDoChangeBackgroundColour(m_mainWidget, (wxColour&) col);
  579. size_t menuCount = GetMenuCount();
  580. for (size_t i = 0; i < menuCount; i++)
  581. m_menus.Item(i)->GetData()->SetBackgroundColour((wxColour&) col);
  582. return true;
  583. }
  584. bool wxMenuBar::SetForegroundColour(const wxColour& col)
  585. {
  586. if (!wxWindowBase::SetForegroundColour(col))
  587. return false;
  588. if (!col.IsOk())
  589. return false;
  590. if (m_mainWidget)
  591. wxDoChangeForegroundColour(m_mainWidget, (wxColour&) col);
  592. size_t menuCount = GetMenuCount();
  593. for (size_t i = 0; i < menuCount; i++)
  594. m_menus.Item(i)->GetData()->SetForegroundColour((wxColour&) col);
  595. return true;
  596. }
  597. void wxMenuBar::ChangeFont(bool WXUNUSED(keepOriginalSize))
  598. {
  599. // Nothing to do for menubar, fonts are kept in wxMenus
  600. }
  601. bool wxMenuBar::SetFont(const wxFont& font)
  602. {
  603. m_font = font;
  604. ChangeFont();
  605. size_t menuCount = GetMenuCount();
  606. for (size_t i = 0; i < menuCount; i++)
  607. m_menus.Item(i)->GetData()->SetFont(font);
  608. return true;
  609. }