guiMenuBar.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "gui/editor/guiMenuBar.h"
  24. #include "console/consoleTypes.h"
  25. #include "console/console.h"
  26. #include "gui/core/guiCanvas.h"
  27. #include "gui/core/guiDefaultControlRender.h"
  28. #include "gui/controls/guiTextListCtrl.h"
  29. #include "sim/actionMap.h"
  30. #include "gfx/gfxDevice.h"
  31. #include "gfx/gfxDrawUtil.h"
  32. #include "gfx/primBuilder.h"
  33. #include "console/engineAPI.h"
  34. #include "gui/editor/guiPopupMenuCtrl.h"
  35. // menu bar:
  36. // basic idea - fixed height control bar at the top of a window, placed and sized in gui editor
  37. // menu text for menus or menu items should not begin with a digit
  38. // all menus can be removed via the clearMenus() console command
  39. // each menu is added via the addMenu(menuText, menuId) console command
  40. // each menu is added with a menu id
  41. // menu items are added to menus via that addMenuItem(menu, menuItemText, menuItemId, accelerator, checkGroup) console command
  42. // each menu item is added with a menu item id and an optional accelerator
  43. // menu items are initially enabled, but can be disabled/re-enabled via the setMenuItemEnable(menu,menuItem,bool)
  44. // menu text can be set via the setMenuText(menu, newMenuText) console method
  45. // menu item text can be set via the setMenuItemText console method
  46. // menu items can be removed via the removeMenuItem(menu, menuItem) console command
  47. // menu items can be cleared via the clearMenuItems(menu) console command
  48. // menus can be hidden or shown via the setMenuVisible(menu, bool) console command
  49. // menu items can be hidden or shown via the setMenuItemVisible(menu, menuItem, bool) console command
  50. // menu items can be check'd via the setMenuItemChecked(menu, menuItem, bool) console command
  51. // if the bool is true, any other items in that menu item's check group become unchecked.
  52. //
  53. // menu items can have a bitmap set on them via the setMenuItemBitmap(menu, menuItem, bitmapIndex)
  54. // passing -1 for the bitmap index will result in no bitmap being shown
  55. // the index paramater is an index into the bitmap array of the associated profile
  56. // this can be used, for example, to display a check next to a selected menu item
  57. // bitmap indices are actually multiplied by 3 when indexing into the bitmap
  58. // since bitmaps have normal, selected and disabled states.
  59. //
  60. // menus can be removed via the removeMenu console command
  61. // specification arguments for menus and menu items can be either the id or the text of the menu or menu item
  62. // adding the menu item "-" will add an un-selectable seperator to the menu
  63. // callbacks:
  64. // when a menu is clicked, before it is displayed, the menu calls its onMenuSelect(menuId, menuText) method -
  65. // this allows the callback to enable/disable menu items, or add menu items in a context-sensitive way
  66. // when a menu item is clicked, the menu removes itself from display, then calls onMenuItemSelect(menuId, menuText, menuItemId, menuItemText)
  67. // the initial implementation does not support:
  68. // hierarchal menus
  69. // keyboard accelerators on menu text (i.e. via alt-key combos)
  70. //------------------------------------------------------------------------------
  71. IMPLEMENT_CONOBJECT(GuiMenuBar);
  72. ConsoleDocClass( GuiMenuBar,
  73. "@brief GUI Control which displays a horizontal bar with individual drop-down menu items. Each menu item may also have submenu items.\n\n"
  74. "@tsexample\n"
  75. "new GuiMenuBar(newMenuBar)\n"
  76. "{\n"
  77. " Padding = \"0\";\n"
  78. " //Properties not specific to this control have been omitted from this example.\n"
  79. "};\n\n"
  80. "// Add a menu to the menu bar\n"
  81. "newMenuBar.addMenu(0,\"New Menu\");\n\n"
  82. "// Add a menu item to the New Menu\n"
  83. "newMenuBar.addMenuItem(0,\"New Menu Item\",0,\"n\",-1);\n\n"
  84. "// Add a submenu item to the New Menu Item\n"
  85. "newMenuBar.addSubmenuItem(0,1,\"New Submenu Item\",0,\"s\",-1);\n"
  86. "@endtsexample\n\n"
  87. "@see GuiTickCtrl\n\n"
  88. "@ingroup GuiCore\n"
  89. );
  90. IMPLEMENT_CALLBACK( GuiMenuBar, onMouseInMenu, void, (bool isInMenu),( isInMenu ),
  91. "@brief Called whenever the mouse enters, or persists is in the menu.\n\n"
  92. "@param isInMenu True if the mouse has entered the menu, otherwise is false.\n"
  93. "@note To receive this callback, call setProcessTicks(true) on the menu bar.\n"
  94. "@tsexample\n"
  95. "// Mouse enters or persists within the menu, causing the callback to occur.\n"
  96. "GuiMenuBar::onMouseInMenu(%this,%hasLeftMenu)\n"
  97. "{\n"
  98. " // Code to run when the callback occurs\n"
  99. "}\n"
  100. "@endtsexample\n\n"
  101. "@see GuiTickCtrl\n\n"
  102. );
  103. IMPLEMENT_CALLBACK( GuiMenuBar, onMenuSelect, void, ( S32 menuId, const char* menuText ),( menuId , menuText ),
  104. "@brief Called whenever a menu is selected.\n\n"
  105. "@param menuId Index id of the clicked menu\n"
  106. "@param menuText Text of the clicked menu\n\n"
  107. "@tsexample\n"
  108. "// A menu has been selected, causing the callback to occur.\n"
  109. "GuiMenuBar::onMenuSelect(%this,%menuId,%menuText)\n"
  110. "{\n"
  111. " // Code to run when the callback occurs\n"
  112. "}\n"
  113. "@endtsexample\n\n"
  114. "@see GuiTickCtrl\n\n"
  115. );
  116. IMPLEMENT_CALLBACK( GuiMenuBar, onMenuItemSelect, void, ( S32 menuId, const char* menuText, S32 menuItemId, const char* menuItemText ),
  117. ( menuId, menuText, menuItemId, menuItemText ),
  118. "@brief Called whenever an item in a menu is selected.\n\n"
  119. "@param menuId Index id of the menu which contains the selected menu item\n"
  120. "@param menuText Text of the menu which contains the selected menu item\n\n"
  121. "@param menuItemId Index id of the selected menu item\n"
  122. "@param menuItemText Text of the selected menu item\n\n"
  123. "@tsexample\n"
  124. "// A menu item has been selected, causing the callback to occur.\n"
  125. "GuiMenuBar::onMenuItemSelect(%this,%menuId,%menuText,%menuItemId,%menuItemText)\n"
  126. "{\n"
  127. " // Code to run when the callback occurs\n"
  128. "}\n"
  129. "@endtsexample\n\n"
  130. "@see GuiTickCtrl\n\n"
  131. );
  132. //------------------------------------------------------------------------------
  133. // initialization, input and render methods
  134. //------------------------------------------------------------------------------
  135. GuiMenuBar::GuiMenuBar()
  136. {
  137. //mMenuList.clear();
  138. menuBarDirty = true;
  139. mouseDownMenu = NULL;
  140. mouseOverMenu = NULL;
  141. mCurAcceleratorIndex = 0;
  142. mPadding = 0;
  143. mCheckmarkBitmapIndex = 0; // Default to the first image in the bitmap array for the check mark
  144. mHorizontalMargin = 6; // Default number of pixels on the left and right side of a manu's text
  145. mVerticalMargin = 1; // Default number of pixels on the top and bottom of a menu's text
  146. mBitmapMargin = 2; // Default number of pixels between a menu's bitmap and text
  147. mMenubarHeight = 24;
  148. // Added:
  149. mouseDownSubmenu = NULL;
  150. mouseOverSubmenu = NULL;
  151. mMouseInMenu = false;
  152. setProcessTicks(false);
  153. }
  154. void GuiMenuBar::onRemove()
  155. {
  156. GuiPopupMenuBackgroundCtrl* backgroundCtrl;
  157. if (Sim::findObject("PopUpMenuControl", backgroundCtrl))
  158. {
  159. if (backgroundCtrl->mMenuBarCtrl == this)
  160. backgroundCtrl->mMenuBarCtrl = nullptr;
  161. }
  162. Parent::onRemove();
  163. }
  164. void GuiMenuBar::initPersistFields()
  165. {
  166. docsURL;
  167. addField("padding", TypeS32, Offset( mPadding, GuiMenuBar ),"Extra padding to add to the bounds of the control.\n");
  168. addField("menubarHeight", TypeS32, Offset(mMenubarHeight, GuiMenuBar), "Sets the height of the menubar when attached to the canvas.\n");
  169. Parent::initPersistFields();
  170. }
  171. bool GuiMenuBar::onWake()
  172. {
  173. if(!Parent::onWake())
  174. return false;
  175. mProfile->constructBitmapArray(); // if a bitmap was specified...
  176. maxBitmapSize.set(0,0);
  177. S32 numBitmaps = mProfile->mBitmapArrayRects.size();
  178. if(numBitmaps)
  179. {
  180. RectI *bitmapBounds = mProfile->mBitmapArrayRects.address();
  181. for(S32 i = 0; i < numBitmaps; i++)
  182. {
  183. if(bitmapBounds[i].extent.x > maxBitmapSize.x)
  184. maxBitmapSize.x = bitmapBounds[i].extent.x;
  185. if(bitmapBounds[i].extent.y > maxBitmapSize.y)
  186. maxBitmapSize.y = bitmapBounds[i].extent.y;
  187. }
  188. }
  189. return true;
  190. }
  191. void GuiMenuBar::addObject(SimObject* object)
  192. {
  193. PopupMenu* popup = dynamic_cast<PopupMenu*>(object);
  194. if (!popup)
  195. {
  196. //if it's not a popup, handle it normally
  197. Parent::addObject(object);
  198. }
  199. else
  200. {
  201. //otherwise, if it IS a popup, don't add it as a child object, but instead just insert it as a menu entry
  202. insert(object, -1);
  203. }
  204. }
  205. GuiMenuBar::MenuEntry *GuiMenuBar::findHitMenu(Point2I mousePoint)
  206. {
  207. Point2I pos = globalToLocalCoord(mousePoint);
  208. for (U32 i = 0; i < mMenuList.size(); ++i)
  209. {
  210. if (mMenuList[i].visible && mMenuList[i].bounds.pointInRect(pos))
  211. return &mMenuList[i];
  212. }
  213. return NULL;
  214. }
  215. void GuiMenuBar::onPreRender()
  216. {
  217. setHeight(mMenubarHeight);
  218. Parent::onPreRender();
  219. if (menuBarDirty)
  220. {
  221. menuBarDirty = false;
  222. U32 curX = mPadding;
  223. for (U32 i = 0; i < mMenuList.size(); ++i)
  224. {
  225. if (!mMenuList[i].visible)
  226. continue;
  227. // Bounds depends on if there is a bitmap to be drawn or not
  228. if (mMenuList[i].bitmapIndex == -1)
  229. {
  230. // Text only
  231. mMenuList[i].bounds.set(curX, 0, mProfile->mFont->getStrWidth(mMenuList[i].text) + (mHorizontalMargin * 2), getHeight() - (mVerticalMargin * 2));
  232. }
  233. else
  234. {
  235. // Will the bitmap and text be draw?
  236. if (!mMenuList[i].drawBitmapOnly)
  237. {
  238. // Draw the bitmap and the text
  239. RectI *bitmapBounds = mProfile->mBitmapArrayRects.address();
  240. mMenuList[i].bounds.set(curX, 0, bitmapBounds[mMenuList[i].bitmapIndex].extent.x + mProfile->mFont->getStrWidth(mMenuList[i].text) + (mHorizontalMargin * 2), getHeight() + (mVerticalMargin * 2));
  241. }
  242. else
  243. {
  244. // Only the bitmap will be drawn
  245. RectI *bitmapBounds = mProfile->mBitmapArrayRects.address();
  246. mMenuList[i].bounds.set(curX, 0, bitmapBounds[mMenuList[i].bitmapIndex].extent.x + mBitmapMargin + (mHorizontalMargin * 2), getHeight() + (mVerticalMargin * 2));
  247. }
  248. }
  249. curX += mMenuList[i].bounds.extent.x;
  250. }
  251. mouseOverMenu = NULL;
  252. mouseDownMenu = NULL;
  253. }
  254. }
  255. void GuiMenuBar::checkMenuMouseMove(const GuiEvent &event)
  256. {
  257. MenuEntry *hit = findHitMenu(event.mousePoint);
  258. if(hit && hit != mouseDownMenu)
  259. {
  260. // gotta close out the current menu...
  261. mouseDownMenu->popupMenu->hidePopup();
  262. mouseOverMenu = mouseDownMenu = hit;
  263. setUpdate();
  264. onAction();
  265. }
  266. }
  267. void GuiMenuBar::onMouseMove(const GuiEvent &event)
  268. {
  269. MenuEntry *hit = findHitMenu(event.mousePoint);
  270. if (mouseDownMenu != nullptr && hit != nullptr)
  271. {
  272. //we have a standing click, so just update and go
  273. mouseDownMenu = mouseOverMenu = hit;
  274. setUpdate();
  275. onAction();
  276. return;
  277. }
  278. mouseOverMenu = hit;
  279. setUpdate();
  280. }
  281. void GuiMenuBar::onMouseEnter(const GuiEvent &event)
  282. {
  283. onMouseInMenu_callback(true);
  284. mMouseInMenu = true;
  285. }
  286. void GuiMenuBar::onMouseLeave(const GuiEvent &event)
  287. {
  288. if(mouseOverMenu)
  289. setUpdate();
  290. mouseOverMenu = NULL;
  291. mMouseInMenu = false;
  292. }
  293. void GuiMenuBar::onMouseDragged(const GuiEvent &event)
  294. {
  295. }
  296. void GuiMenuBar::onMouseDown(const GuiEvent &event)
  297. {
  298. }
  299. void GuiMenuBar::onMouseUp(const GuiEvent &event)
  300. {
  301. mouseDownMenu = mouseOverMenu = findHitMenu(event.mousePoint);
  302. setUpdate();
  303. onAction();
  304. }
  305. void GuiMenuBar::onRender(Point2I offset, const RectI &updateRect)
  306. {
  307. Point2I extent = getExtent();
  308. RectI ctrlRect(offset, extent);
  309. GFXDrawUtil* drawUtil = GFX->getDrawUtil();
  310. //if opaque, fill the update rect with the fill color
  311. if (mProfile->mOpaque)
  312. drawUtil->drawRectFill(RectI(offset, extent), mProfile->mFillColor);
  313. //if there's a border, draw the border
  314. if (mProfile->mBorder)
  315. renderBorder(ctrlRect, mProfile);
  316. for (U32 i = 0; i < mMenuList.size(); ++i)
  317. {
  318. if (!mMenuList[i].visible)
  319. continue;
  320. ColorI fontColor = mProfile->mFontColor;
  321. RectI bounds = mMenuList[i].bounds;
  322. bounds.point += offset;
  323. Point2I start;
  324. start.x = mMenuList[i].bounds.point.x + mHorizontalMargin;
  325. start.y = mMenuList[i].bounds.point.y + (mMenuList[i].bounds.extent.y - mProfile->mFont->getHeight()) / 2;
  326. // Draw the border
  327. if (mMenuList[i].drawBorder)
  328. {
  329. RectI highlightBounds = bounds;
  330. highlightBounds.inset(1, 1);
  331. if (&mMenuList[i] == mouseDownMenu)
  332. renderFilledBorder(highlightBounds, mProfile->mBorderColorHL, mProfile->mFillColorHL);
  333. else if (&mMenuList[i] == mouseOverMenu && mouseDownMenu == NULL)
  334. renderFilledBorder(highlightBounds, mProfile->mBorderColorHL, mProfile->mFillColorHL);
  335. }
  336. // Do we draw a bitmap?
  337. if (mMenuList[i].bitmapIndex != -1)
  338. {
  339. S32 index = mMenuList[i].bitmapIndex * 3;
  340. if (&mMenuList[i] == mouseDownMenu)
  341. ++index;
  342. else if (&mMenuList[i] == mouseOverMenu && mouseDownMenu == NULL)
  343. index += 2;
  344. RectI rect = mProfile->mBitmapArrayRects[index];
  345. Point2I bitmapstart(start);
  346. bitmapstart.y = mMenuList[i].bounds.point.y + (mMenuList[i].bounds.extent.y - rect.extent.y) / 2;
  347. drawUtil->clearBitmapModulation();
  348. drawUtil->drawBitmapSR(mProfile->getBitmap(), offset + bitmapstart, rect);
  349. // Should we also draw the text?
  350. if (!mMenuList[i].drawBitmapOnly)
  351. {
  352. start.x += mBitmapMargin;
  353. drawUtil->setBitmapModulation(fontColor);
  354. drawUtil->drawText(mProfile->mFont, start + offset, mMenuList[i].text, mProfile->mFontColors);
  355. }
  356. }
  357. else
  358. {
  359. drawUtil->setBitmapModulation(fontColor);
  360. drawUtil->drawText(mProfile->mFont, start + offset, mMenuList[i].text, mProfile->mFontColors);
  361. }
  362. }
  363. renderChildControls(offset, updateRect);
  364. }
  365. void GuiMenuBar::buildWindowAcceleratorMap(WindowInputGenerator &inputGenerator)
  366. {
  367. // ok, accelerator map is cleared...
  368. // add all our keys:
  369. mCurAcceleratorIndex = 1;
  370. for (U32 i = 0; i < mMenuList.size(); ++i)
  371. {
  372. for (U32 item = 0; item < mMenuList[i].popupMenu->mMenuItems.size(); item++)
  373. {
  374. if (!mMenuList[i].popupMenu->mMenuItems[item].mAccelerator)
  375. {
  376. mMenuList[i].popupMenu->mMenuItems[item].mAccelerator = 0;
  377. continue;
  378. }
  379. EventDescriptor accelEvent;
  380. ActionMap::createEventDescriptor(mMenuList[i].popupMenu->mMenuItems[item].mAccelerator, &accelEvent);
  381. //now we have a modifier, and a key, add them to the canvas
  382. inputGenerator.addAcceleratorKey(this, mMenuList[i].popupMenu->mMenuItems[item].mCMD, accelEvent.eventCode, accelEvent.flags);
  383. mMenuList[i].popupMenu->mMenuItems[item].mAcceleratorIndex = mCurAcceleratorIndex;
  384. mCurAcceleratorIndex++;
  385. }
  386. }
  387. }
  388. void GuiMenuBar::removeWindowAcceleratorMap( WindowInputGenerator &inputGenerator )
  389. {
  390. inputGenerator.removeAcceleratorKeys( this );
  391. }
  392. void GuiMenuBar::acceleratorKeyPress(U32 index)
  393. {
  394. // loop through all the menus
  395. // and find the item that corresponds to the accelerator index
  396. for (U32 i = 0; i < mMenuList.size(); ++i)
  397. {
  398. if (!mMenuList[i].visible)
  399. continue;
  400. for(U32 item = 0; item < mMenuList[i].popupMenu->mMenuItems.size(); item++)
  401. {
  402. if(mMenuList[i].popupMenu->mMenuItems[item].mAcceleratorIndex == index)
  403. {
  404. // first, call the script callback for menu selection:
  405. onMenuSelect_callback(mMenuList[i].popupMenu->getId(), mMenuList[i].text);
  406. return;
  407. }
  408. }
  409. }
  410. }
  411. void GuiMenuBar::onSleep()
  412. {
  413. Parent::onSleep();
  414. }
  415. //------------------------------------------------------------------------------
  416. void GuiMenuBar::onAction()
  417. {
  418. if(!mouseDownMenu)
  419. return;
  420. mouseDownMenu->popupMenu->hidePopup();
  421. // first, call the script callback for menu selection:
  422. onMenuSelect_callback(mouseDownMenu->popupMenu->getId(), mouseDownMenu->text);
  423. mouseDownMenu->popupMenu->mMenuBarCtrl = this;
  424. GuiCanvas *root = getRoot();
  425. Point2I pos = Point2I(mouseDownMenu->bounds.point.x, mouseDownMenu->bounds.point.y + mouseDownMenu->bounds.extent.y);
  426. mouseDownMenu->popupMenu->showPopup(root, pos.x, pos.y);
  427. }
  428. // Process a tick
  429. void GuiMenuBar::processTick()
  430. {
  431. if(mMouseInMenu)
  432. onMouseInMenu_callback(true);
  433. }
  434. void GuiMenuBar::insert(SimObject* pObject, S32 pos)
  435. {
  436. PopupMenu* menu = dynamic_cast<PopupMenu*>(pObject);
  437. if (menu == nullptr)
  438. {
  439. Con::errorf("GuiMenuBar::insert() - attempted to insert non-popupMenu object: %d", pObject->getId());
  440. return;
  441. }
  442. MenuEntry newMenu;
  443. newMenu.pos = pos >= mMenuList.size() || pos == -1 ? pos = mMenuList.size() : pos;
  444. newMenu.drawBitmapOnly = false;
  445. newMenu.drawBorder = true;
  446. newMenu.bitmapIndex = -1;
  447. newMenu.text = menu->mBarTitle;
  448. newMenu.visible = true;
  449. newMenu.popupMenu = menu;
  450. if (pos >= mMenuList.size() || pos == -1)
  451. mMenuList.push_back(newMenu);
  452. else
  453. mMenuList.insert(pos, newMenu);
  454. menuBarDirty = true; //ensure we refresh
  455. }
  456. void GuiMenuBar::remove(SimObject* pObject)
  457. {
  458. PopupMenu* menu = dynamic_cast<PopupMenu*>(pObject);
  459. if (menu == nullptr)
  460. {
  461. Con::errorf("GuiMenuBar::remove() - attempted to remove non-popupMenu object: %d", pObject->getId());
  462. return;
  463. }
  464. for(U32 i=0; i < mMenuList.size(); i++)
  465. {
  466. if(mMenuList[i].popupMenu == menu)
  467. {
  468. mMenuList.erase(i);
  469. menuBarDirty = true; //ensure we refresh
  470. return;
  471. }
  472. }
  473. }
  474. PopupMenu* GuiMenuBar::getMenu(U32 index)
  475. {
  476. if (index >= mMenuList.size())
  477. return nullptr;
  478. return mMenuList[index].popupMenu;
  479. }
  480. PopupMenu* GuiMenuBar::findMenu(String barTitle)
  481. {
  482. for (U32 i = 0; i < mMenuList.size(); i++)
  483. {
  484. if (String::ToLower(mMenuList[i].text) == String::ToLower(barTitle))
  485. return mMenuList[i].popupMenu;
  486. }
  487. return nullptr;
  488. }
  489. //-----------------------------------------------------------------------------
  490. // Console Methods
  491. //-----------------------------------------------------------------------------
  492. #ifdef TORQUE_TOOLS
  493. DefineEngineMethod(GuiMenuBar, attachToCanvas, void, (const char *canvas, S32 pos), , "(GuiCanvas, pos)")
  494. {
  495. GuiCanvas* canv = dynamic_cast<GuiCanvas*>(Sim::findObject(canvas));
  496. if (canv)
  497. {
  498. canv->setMenuBar(object);
  499. }
  500. }
  501. DefineEngineMethod(GuiMenuBar, removeFromCanvas, void, (), , "()")
  502. {
  503. GuiCanvas* canvas = object->getRoot();
  504. if(canvas)
  505. canvas->setMenuBar(nullptr);
  506. }
  507. #endif
  508. DefineEngineMethod(GuiMenuBar, getMenuCount, S32, (), , "()")
  509. {
  510. return object->getMenuListCount();
  511. }
  512. DefineEngineMethod(GuiMenuBar, getMenu, S32, (S32 index), (0), "(Index)")
  513. {
  514. return object->getMenu(index)->getId();
  515. }
  516. //-----------------------------------------------------------------------------
  517. DefineEngineMethod(GuiMenuBar, insert, void, (SimObject* pObject, S32 pos), (nullAsType<SimObject*>(), -1), "(object, pos) insert object at position")
  518. {
  519. if(pObject == nullptr)
  520. {
  521. Con::errorf("GuiMenuBar::insert() - null object");
  522. return;
  523. }
  524. object->insert(pObject, pos);
  525. }
  526. DefineEngineMethod(GuiMenuBar, remove, void, (SimObject* pObject), (nullAsType<SimObject*>()), "(object, pos) remove object")
  527. {
  528. if (pObject == nullptr)
  529. {
  530. Con::errorf("GuiMenuBar::remove() - null object");
  531. return;
  532. }
  533. object->remove(pObject);
  534. }
  535. DefineEngineMethod(GuiMenuBar, findMenu, S32, (const char* barTitle), (""), "(barTitle)")
  536. {
  537. PopupMenu* menu = object->findMenu(barTitle);
  538. if (menu)
  539. return menu->getId();
  540. else
  541. return 0;
  542. }