guiMenuBar.cpp 21 KB

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