guiMenuBar.cc 60 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2013 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 "console/consoleTypes.h"
  23. #include "console/console.h"
  24. #include "graphics/dgl.h"
  25. #include "gui/guiCanvas.h"
  26. #include "gui/guiDefaultControlRender.h"
  27. #include "gui/guiTextListCtrl.h"
  28. #include "input/actionMap.h"
  29. #include "gui/editor/guiMenuBar.h"
  30. // menu bar:
  31. // basic idea - fixed height control bar at the top of a window, placed and sized in gui editor
  32. // menu text for menus or menu items should not begin with a digit
  33. // all menus can be removed via the clearMenus() console command
  34. // each menu is added via the addMenu(menuText, menuId) console command
  35. // each menu is added with a menu id
  36. // menu items are added to menus via that addMenuItem(menu, menuItemText, menuItemId, accelerator, checkGroup) console command
  37. // each menu item is added with a menu item id and an optional accelerator
  38. // menu items are initially enabled, but can be disabled/re-enabled via the setMenuItemEnable(menu,menuItem,bool)
  39. // menu text can be set via the setMenuText(menu, newMenuText) console method
  40. // menu item text can be set via the setMenuItemText console method
  41. // menu items can be removed via the removeMenuItem(menu, menuItem) console command
  42. // menu items can be cleared via the clearMenuItems(menu) console command
  43. // menus can be hidden or shown via the setMenuVisible(menu, bool) console command
  44. // menu items can be hidden or shown via the setMenuItemVisible(menu, menuItem, bool) console command
  45. // menu items can be check'd via the setMenuItemChecked(menu, menuItem, bool) console command
  46. // if the bool is true, any other items in that menu item's check group become unchecked.
  47. //
  48. // menu items can have a bitmap set on them via the setMenuItemBitmap(menu, menuItem, bitmapIndex)
  49. // passing -1 for the bitmap index will result in no bitmap being shown
  50. // the index paramater is an index into the bitmap array of the associated profile
  51. // this can be used, for example, to display a check next to a selected menu item
  52. // bitmap indices are actually multiplied by 3 when indexing into the bitmap
  53. // since bitmaps have normal, selected and disabled states.
  54. //
  55. // menus can be removed via the removeMenu console command
  56. // specification arguments for menus and menu items can be either the id or the text of the menu or menu item
  57. // adding the menu item "-" will add an un-selectable seperator to the menu
  58. // callbacks:
  59. // when a menu is clicked, before it is displayed, the menu calls its onMenuSelect(menuId, menuText) method -
  60. // this allows the callback to enable/disable menu items, or add menu items in a context-sensitive way
  61. // when a menu item is clicked, the menu removes itself from display, then calls onMenuItemSelect(menuId, menuText, menuItemId, menuItemText)
  62. // the initial implementation does not support:
  63. // hierarchal menus
  64. // keyboard accelerators on menu text (i.e. via alt-key combos)
  65. //------------------------------------------------------------------------------
  66. IMPLEMENT_CONOBJECT(GuiMenuBar);
  67. //------------------------------------------------------------------------------
  68. // console methods
  69. //------------------------------------------------------------------------------
  70. ConsoleMethod(GuiMenuBar, clearMenus, void, 2, 2, "() Clears all menus and sub-menus from the menu bar.\n"
  71. "@return No return value")
  72. {
  73. object->clearMenus();
  74. }
  75. ConsoleMethod(GuiMenuBar, setMenuMargins, void, 5, 5, "(S32 horizontalMargin, S32 verticalMargin, S32 bitmapToTextSpacing) Sets the menu rendering margins: horizontal, vertical, bitmap spacing.")
  76. {
  77. object->mHorizontalMargin = dAtoi(argv[2]);
  78. object->mVerticalMargin = dAtoi(argv[3]);
  79. object->mBitmapMargin = dAtoi(argv[4]);
  80. }
  81. ConsoleMethod(GuiMenuBar, addMenu, void, 4, 4, "( menuName , menuID ) Adds a new menu to the menu bar.\n"
  82. "@param menuName The text (name) of the new menu entry.\n"
  83. "@param menuID The ID of the new menu entry.\n"
  84. "@return No return value")
  85. {
  86. if(dIsdigit(argv[2][0]))
  87. {
  88. Con::errorf("Cannot add menu %s (id = %s). First character of a menu's text cannot be a digit.", argv[2], argv[3]);
  89. return;
  90. }
  91. object->addMenu(argv[2], dAtoi(argv[3]));
  92. }
  93. ConsoleMethod(GuiMenuBar, addMenuItem, void, 5, 7, "( menuID | menuName , menuItemName , menuItemID , [ accelerator ] , [ checkGroup ] ) Adds a sub-menu entry to the specified menu.\n"
  94. "@param menuID The ID of the menu.\n"
  95. "@param menuName The text (name) of the menu.\n"
  96. "@param menuItemID The ID of the menu item.\n"
  97. "@param menuItemName The text (name) of the menu item.\n"
  98. "@param accelerator A boolean value. If set to true, the sub-menu entry is checked, otherwise it is unchecked.\n"
  99. "@param checkGroup The check group this item should belong to, if any.\n"
  100. "@return No return value")
  101. {
  102. if(dIsdigit(argv[3][0]))
  103. {
  104. Con::errorf("Cannot add menu item %s (id = %s). First character of a menu item's text cannot be a digit.", argv[3], argv[4]);
  105. return;
  106. }
  107. GuiMenuBar::Menu *menu = object->findMenu(argv[2]);
  108. if(!menu)
  109. {
  110. Con::errorf("Cannot find menu %s for addMenuItem.", argv[2]);
  111. return;
  112. }
  113. object->addMenuItem(menu, argv[3], dAtoi(argv[4]), argc == 5 ? "" : argv[5], argc < 7 ? -1 : dAtoi(argv[6]));
  114. }
  115. ConsoleMethod(GuiMenuBar, setMenuItemEnable, void, 5, 5, "( menuID | menuName , menuItemID | menuItemName , enabled ) Sets the menu item to enabled or disabled.\n"
  116. "@param menuID The ID of the menu.\n"
  117. "@param menuName The text (name) of the menu.\n"
  118. "@param menuItemID The ID of the menu item.\n"
  119. "@param menuItemName The text (name) of the menu item.\n"
  120. "@param enabled A boolean value. If set to true, the sub-menu entry is enabled, otherwise it is disabled.\n"
  121. "@return No return value")
  122. {
  123. GuiMenuBar::Menu *menu = object->findMenu(argv[2]);
  124. if(!menu)
  125. {
  126. Con::errorf("Cannot find menu %s for setMenuItemEnable.", argv[2]);
  127. return;
  128. }
  129. GuiMenuBar::MenuItem *menuItem = object->findMenuItem(menu, argv[3]);
  130. if(!menuItem)
  131. {
  132. Con::errorf("Cannot find menu item %s for setMenuItemEnable.", argv[3]);
  133. return;
  134. }
  135. menuItem->enabled = dAtob(argv[4]);
  136. }
  137. ConsoleMethod(GuiMenuBar, setCheckmarkBitmapIndex, void, 3, 3, "(S32 bitmapindex) - sets the menu bitmap index for the check mark image.\n"
  138. "@return No Return Value.")
  139. {
  140. object->mCheckmarkBitmapIndex = dAtoi(argv[2]);
  141. }
  142. ConsoleMethod(GuiMenuBar, setMenuItemChecked, void, 5, 5, "( menuID | menuName , menuItemID | menuItemName , checked ) Sets the menu item bitmap to a check mark, which must be the first element in the bitmap array. Any other menu items in the menu with the same check group become unchecked if they are checked.\n"
  143. "@param menuID The ID of the menu.\n"
  144. "@param menuName The text (name) of the menu.\n"
  145. "@param menuItemID The ID of the menu item.\n"
  146. "@param menuItemName The text (name) of the menu item.\n"
  147. "@param checked A boolean value. If set to true, the sub-menu entry is checked, otherwise it is unchecked.\n"
  148. "@return No return value")
  149. {
  150. GuiMenuBar::Menu *menu = object->findMenu(argv[2]);
  151. if(!menu)
  152. {
  153. Con::errorf("Cannot find menu %s for setMenuItemChecked.", argv[2]);
  154. return;
  155. }
  156. GuiMenuBar::MenuItem *menuItem = object->findMenuItem(menu, argv[3]);
  157. if(!menuItem)
  158. {
  159. Con::errorf("Cannot find menu item %s for setMenuItemChecked.", argv[3]);
  160. return;
  161. }
  162. bool checked = dAtob(argv[4]);
  163. if(checked && menuItem->checkGroup != -1)
  164. {
  165. // first, uncheck everything in the group:
  166. for(GuiMenuBar::MenuItem *itemWalk = menu->firstMenuItem; itemWalk; itemWalk = itemWalk->nextMenuItem)
  167. if(itemWalk->checkGroup == menuItem->checkGroup && itemWalk->bitmapIndex == object->mCheckmarkBitmapIndex)
  168. itemWalk->bitmapIndex = -1;
  169. }
  170. menuItem->bitmapIndex = checked ? object->mCheckmarkBitmapIndex : -1;
  171. }
  172. ConsoleMethod(GuiMenuBar, setMenuText, void, 4, 4, "( menuID | menuName , newMenuText ) Sets the text of the specified menu to the new string.\n"
  173. "@param menuID The ID of the menu.\n"
  174. "@param menuName The text (name) of the menu.\n"
  175. "@param newMenuText The new text to give the menu entry.\n"
  176. "@return No return value")
  177. {
  178. if(dIsdigit(argv[3][0]))
  179. {
  180. Con::errorf("Cannot name menu %s to %s. First character of a menu's text cannot be a digit.", argv[2], argv[3]);
  181. return;
  182. }
  183. GuiMenuBar::Menu *menu = object->findMenu(argv[2]);
  184. if(!menu)
  185. {
  186. Con::errorf("Cannot find menu %s for setMenuText.", argv[2]);
  187. return;
  188. }
  189. dFree(menu->text);
  190. menu->text = dStrdup(argv[3]);
  191. object->menuBarDirty = true;
  192. }
  193. ConsoleMethod(GuiMenuBar, setMenuBitmapIndex, void, 6, 6, "(string menu, S32 bitmapindex, bool bitmaponly, bool drawborder) Sets the bitmap index for the menu and toggles rendering only the bitmap.\n"
  194. "@return No return value.")
  195. {
  196. GuiMenuBar::Menu *menu = object->findMenu(argv[2]);
  197. if(!menu)
  198. {
  199. Con::errorf("Cannot find menu %s for setMenuBitmapIndex.", argv[2]);
  200. return;
  201. }
  202. menu->bitmapIndex = dAtoi(argv[3]);
  203. menu->drawBitmapOnly = dAtob(argv[4]);
  204. menu->drawBorder = dAtob(argv[5]);
  205. object->menuBarDirty = true;
  206. }
  207. ConsoleMethod(GuiMenuBar, setMenuVisible, void, 4, 4, "( menuID | menuName , visible ) Use the setMenuVisible method to enable or disable the visibility of a specific menu entry.\n"
  208. "@param menuID The ID of the menu.\n"
  209. "@param menuName The text (name) of the menu.\n"
  210. "@param visible A boolean value. If set to true, this menu entry will be shown, otherwise it will be hidden.\n"
  211. "@return No return value")
  212. {
  213. GuiMenuBar::Menu *menu = object->findMenu(argv[2]);
  214. if(!menu)
  215. {
  216. Con::errorf("Cannot find menu %s for setMenuVisible.", argv[2]);
  217. return;
  218. }
  219. menu->visible = dAtob(argv[3]);
  220. object->menuBarDirty = true;
  221. object->setUpdate();
  222. }
  223. ConsoleMethod(GuiMenuBar, setMenuItemText, void, 5, 5, "( menuID | menuName , menuItemID | menuItemName , newMenuItemText ) Sets the text of the specified menu item to the new string.\n"
  224. "@param menuID The ID of the menu.\n"
  225. "@param menuName The text (name) of the menu.\n"
  226. "@param menuItemID The ID of the menu item.\n"
  227. "@param menuItemName The text (name) of the menu item.\n"
  228. "@param newMenuItemText The new text for the specified sub-menu entry.\n"
  229. "@return No return value")
  230. {
  231. if(dIsdigit(argv[4][0]))
  232. {
  233. Con::errorf("Cannot name menu item %s to %s. First character of a menu item's text cannot be a digit.", argv[3], argv[4]);
  234. return;
  235. }
  236. GuiMenuBar::Menu *menu = object->findMenu(argv[2]);
  237. if(!menu)
  238. {
  239. Con::errorf("Cannot find menu %s for setMenuItemText.", argv[2]);
  240. return;
  241. }
  242. GuiMenuBar::MenuItem *menuItem = object->findMenuItem(menu, argv[3]);
  243. if(!menuItem)
  244. {
  245. Con::errorf("Cannot find menu item %s for setMenuItemText.", argv[3]);
  246. return;
  247. }
  248. dFree(menuItem->text);
  249. menuItem->text = dStrdup(argv[4]);
  250. }
  251. ConsoleMethod(GuiMenuBar, setMenuItemVisible, void, 5, 5, "( menuID | menuName, menuItemID | menuItemName, visible ) Use the setMenuItemVisible method to enable or disable the visibility of a specific sub-menu entry.\n"
  252. "@param menuID The ID of the menu.\n"
  253. "@param menuName The text (name) of the menu.\n"
  254. "@param menuItemID The ID of the menu item.\n"
  255. "@param menuItemName The text (name) of the menu item.\n"
  256. "@param visible A boolean value. If set to true, this sub-menu entry will be shown, otherwise it will be hidden.\n"
  257. "@return No return value")
  258. {
  259. GuiMenuBar::Menu *menu = object->findMenu(argv[2]);
  260. if(!menu)
  261. {
  262. Con::errorf("Cannot find menu %s for setMenuItemVisible.", argv[2]);
  263. return;
  264. }
  265. GuiMenuBar::MenuItem *menuItem = object->findMenuItem(menu, argv[3]);
  266. if(!menuItem)
  267. {
  268. Con::errorf("Cannot find menu item %s for setMenuItemVisible.", argv[3]);
  269. return;
  270. }
  271. menuItem->visible = dAtob(argv[4]);
  272. }
  273. ConsoleMethod(GuiMenuBar, setMenuItemBitmap, void, 5, 5, "( menuID | menuName , menuItemID | menuItemName , bitmapIndex ) Sets the specified menu item bitmap index in the bitmap array. Setting the item's index to -1 will remove any bitmap.\n"
  274. "@param menuID The ID of the menu.\n"
  275. "@param menuName The text (name) of the menu.\n"
  276. "@param menuItemID The ID of the menu item.\n"
  277. "@param menuItemName The text (name) of the menu item.\n"
  278. "@param bitMapIndex An integer value specifying the row of bitmap entries to use for sub-menu entry.\n"
  279. "@return No return value")
  280. {
  281. GuiMenuBar::Menu *menu = object->findMenu(argv[2]);
  282. if(!menu)
  283. {
  284. Con::errorf("Cannot find menu %s for setMenuItemBitmap.", argv[2]);
  285. return;
  286. }
  287. GuiMenuBar::MenuItem *menuItem = object->findMenuItem(menu, argv[3]);
  288. if(!menuItem)
  289. {
  290. Con::errorf("Cannot find menu item %s for setMenuItemBitmap.", argv[3]);
  291. return;
  292. }
  293. menuItem->bitmapIndex = dAtoi(argv[4]);
  294. }
  295. ConsoleMethod(GuiMenuBar, removeMenuItem, void, 4, 4, "( menuID | menuName , menuItemID | menuItemName ) Removes the specified menu item from the menu.\n"
  296. "@param menuID The ID of the menu.\n"
  297. "@param menuName The text (name) of the menu.\n"
  298. "@param menuItemID The ID of the menu item.\n"
  299. "@param menuItemName The text (name) of the menu item.\n"
  300. "@return No return value")
  301. {
  302. GuiMenuBar::Menu *menu = object->findMenu(argv[2]);
  303. if(!menu)
  304. {
  305. Con::errorf("Cannot find menu %s for removeMenuItem.", argv[2]);
  306. return;
  307. }
  308. GuiMenuBar::MenuItem *menuItem = object->findMenuItem(menu, argv[3]);
  309. if(!menuItem)
  310. {
  311. Con::errorf("Cannot find menu item %s for removeMenuItem.", argv[3]);
  312. return;
  313. }
  314. object->removeMenuItem(menu, menuItem);
  315. }
  316. ConsoleMethod(GuiMenuBar, clearMenuItems, void, 3, 3, "( menuID | menuName ) Removes all the sub-menu items from the specified menu.\n"
  317. "@param menuID The ID of the menu.\n"
  318. "@param menuName The text (name) of the menu.\n"
  319. "@return No return value")
  320. {
  321. GuiMenuBar::Menu *menu = object->findMenu(argv[2]);
  322. if(!menu)
  323. {
  324. //Con::errorf("Cannot find menu %s for clearMenuItems.", argv[2]);
  325. return;
  326. }
  327. object->clearMenuItems(menu);
  328. }
  329. ConsoleMethod(GuiMenuBar, removeMenu, void, 3, 3, "( menuID | menuName ) Removes the specified menu from the menu bar.\n"
  330. "@param menuID The ID of the menu.\n"
  331. "@param menuName The text (name) of the menu.\n"
  332. "@param menuItemID The ID of the menu item.\n"
  333. "@param menuItemName The text (name) of the menu item.\n"
  334. "@param checked A boolean value. If set to true, the sub-menu entry is checked, otherwise it is unchecked.\n"
  335. "@return No return value")
  336. {
  337. GuiMenuBar::Menu *menu = object->findMenu(argv[2]);
  338. if(!menu)
  339. {
  340. //Con::errorf("Cannot find menu %s for removeMenu.", argv[2]);
  341. return;
  342. }
  343. object->clearMenuItems(menu);
  344. object->menuBarDirty = true;
  345. }
  346. //------------------------------------------------------------------------------
  347. // DAW: Submenu console methods
  348. //------------------------------------------------------------------------------
  349. ConsoleMethod(GuiMenuBar, setMenuItemSubmenuState, void, 5, 5, "(string menu, string menuItem, bool isSubmenu) Sets the given menu item to be a submenu\n"
  350. "@param menu The menu where the sub menu is located.\n"
  351. "@param menuItem The menu item to set as a sub menu.\n"
  352. "@param inSubmenu A boolean value signifying whether or not it is a submenu.\n"
  353. "@return No return value.")
  354. {
  355. GuiMenuBar::Menu *menu = object->findMenu(argv[2]);
  356. if(!menu)
  357. {
  358. Con::errorf("Cannot find menu %s for setMenuItemSubmenuState.", argv[2]);
  359. return;
  360. }
  361. GuiMenuBar::MenuItem *menuitem = object->findMenuItem(menu, argv[3]);
  362. if(!menuitem)
  363. {
  364. Con::errorf("Cannot find menuitem %s for setMenuItemSubmenuState.", argv[3]);
  365. return;
  366. }
  367. menuitem->isSubmenu = dAtob(argv[4]);
  368. }
  369. ConsoleMethod(GuiMenuBar, addSubmenuItem, void, 6, 8, "(string menu, string menuItem, string submenuItemText, int submenuItemId, string accelerator = NULL, int checkGroup = -1) Adds a menu item to the specified menu. The menu argument can be either the text of a menu or its id.")
  370. {
  371. if(dIsdigit(argv[4][0]))
  372. {
  373. Con::errorf("Cannot add submenu item %s (id = %s). First character of a menu item's text cannot be a digit.", argv[4], argv[5]);
  374. return;
  375. }
  376. GuiMenuBar::Menu *menu = object->findMenu(argv[2]);
  377. if(!menu)
  378. {
  379. Con::errorf("Cannot find menu %s for addMenuItem.", argv[2]);
  380. return;
  381. }
  382. GuiMenuBar::MenuItem *menuitem = object->findMenuItem(menu, argv[3]);
  383. if(!menuitem)
  384. {
  385. Con::errorf("Cannot find menuitem %s for addSubmenuItem.", argv[3]);
  386. return;
  387. }
  388. object->addSubmenuItem(menu, menuitem, argv[4], dAtoi(argv[5]), argc == 6 ? "" : argv[6], argc < 8 ? -1 : dAtoi(argv[7]));
  389. }
  390. ConsoleMethod(GuiMenuBar, clearSubmenuItems, void, 4, 4, "(string menu, string menuItem) Removes all the menu items from the specified submenu.\n"
  391. "@return No return value.")
  392. {
  393. GuiMenuBar::Menu *menu = object->findMenu(argv[2]);
  394. if(!menu)
  395. {
  396. Con::errorf("Cannot find menu %s for clearSubmenuItems.", argv[2]);
  397. return;
  398. }
  399. GuiMenuBar::MenuItem *menuitem = object->findMenuItem(menu, argv[3]);
  400. if(!menuitem)
  401. {
  402. Con::errorf("Cannot find menuitem %s for clearSubmenuItems.", argv[3]);
  403. return;
  404. }
  405. object->clearSubmenuItems(menuitem);
  406. }
  407. ConsoleMethod(GuiMenuBar, setSubmenuItemChecked, void, 6, 6, "(string menu, string menuItem, string submenuItemText, bool checked) Sets the menu item bitmap to a check mark, which by default is the first element in the bitmap array (although this may be changed with setCheckmarkBitmapIndex()). Any other menu items in the menu with the same check group become unchecked if they are checked.")
  408. {
  409. // Find the parent menu
  410. GuiMenuBar::Menu *menu = object->findMenu(argv[2]);
  411. if(!menu)
  412. {
  413. Con::errorf("Cannot find menu %s for setSubmenuItemChecked.", argv[2]);
  414. return;
  415. }
  416. // Find the parent menu item
  417. GuiMenuBar::MenuItem *menuItem = object->findMenuItem(menu, argv[3]);
  418. if(!menuItem)
  419. {
  420. Con::errorf("Cannot find menu item %s for setSubmenuItemChecked.", argv[3]);
  421. return;
  422. }
  423. // Find the submenu item
  424. GuiMenuBar::MenuItem *submenuItem = object->findSubmenuItem(menu, argv[3], argv[4]);
  425. if(!submenuItem)
  426. {
  427. Con::errorf("Cannot find submenu item %s for setSubmenuItemChecked.", argv[4]);
  428. return;
  429. }
  430. bool checked = dAtob(argv[5]);
  431. if(checked && submenuItem->checkGroup != -1)
  432. {
  433. // first, uncheck everything in the group:
  434. for(GuiMenuBar::MenuItem *itemWalk = menuItem->firstSubmenuItem; itemWalk; itemWalk = itemWalk->nextMenuItem)
  435. if(itemWalk->checkGroup == submenuItem->checkGroup && itemWalk->bitmapIndex == object->mCheckmarkBitmapIndex)
  436. itemWalk->bitmapIndex = -1;
  437. }
  438. submenuItem->bitmapIndex = checked ? object->mCheckmarkBitmapIndex : -1;
  439. }
  440. //------------------------------------------------------------------------------
  441. // menu management methods
  442. //------------------------------------------------------------------------------
  443. void GuiMenuBar::addMenu(const char *menuText, U32 menuId)
  444. {
  445. // allocate the menu
  446. Menu *newMenu = new Menu;
  447. newMenu->text = dStrdup(menuText);
  448. newMenu->id = menuId;
  449. newMenu->nextMenu = NULL;
  450. newMenu->firstMenuItem = NULL;
  451. newMenu->visible = true;
  452. // Menu bitmap variables
  453. newMenu->bitmapIndex = -1;
  454. newMenu->drawBitmapOnly = false;
  455. newMenu->drawBorder = true;
  456. // add it to the menu list
  457. menuBarDirty = true;
  458. Menu **walk;
  459. for(walk = &menuList; *walk; walk = &(*walk)->nextMenu)
  460. ;
  461. *walk = newMenu;
  462. }
  463. GuiMenuBar::Menu *GuiMenuBar::findMenu(const char *menu)
  464. {
  465. if(dIsdigit(menu[0]))
  466. {
  467. U32 id = dAtoi(menu);
  468. for(Menu *walk = menuList; walk; walk = walk->nextMenu)
  469. if(id == walk->id)
  470. return walk;
  471. return NULL;
  472. }
  473. else
  474. {
  475. for(Menu *walk = menuList; walk; walk = walk->nextMenu)
  476. if(!dStricmp(menu, walk->text))
  477. return walk;
  478. return NULL;
  479. }
  480. }
  481. GuiMenuBar::MenuItem *GuiMenuBar::findMenuItem(Menu *menu, const char *menuItem)
  482. {
  483. if(dIsdigit(menuItem[0]))
  484. {
  485. U32 id = dAtoi(menuItem);
  486. for(MenuItem *walk = menu->firstMenuItem; walk; walk = walk->nextMenuItem)
  487. if(id == walk->id)
  488. return walk;
  489. return NULL;
  490. }
  491. else
  492. {
  493. for(MenuItem *walk = menu->firstMenuItem; walk; walk = walk->nextMenuItem)
  494. if(!dStricmp(menuItem, walk->text))
  495. return walk;
  496. return NULL;
  497. }
  498. }
  499. void GuiMenuBar::removeMenu(Menu *menu)
  500. {
  501. menuBarDirty = true;
  502. clearMenuItems(menu);
  503. for(Menu **walk = &menuList; *walk; walk = &(*walk)->nextMenu)
  504. {
  505. if(*walk == menu)
  506. {
  507. *walk = menu->nextMenu;
  508. break;
  509. }
  510. }
  511. dFree(menu->text);
  512. delete menu;
  513. }
  514. void GuiMenuBar::removeMenuItem(Menu *menu, MenuItem *menuItem)
  515. {
  516. for(MenuItem **walk = &menu->firstMenuItem; *walk; walk = &(*walk)->nextMenuItem)
  517. {
  518. if(*walk == menuItem)
  519. {
  520. *walk = menuItem->nextMenuItem;
  521. break;
  522. }
  523. }
  524. // DAW: If this is a submenu, then be sure to clear the submenu's items
  525. if(menuItem->isSubmenu)
  526. {
  527. clearSubmenuItems(menuItem);
  528. }
  529. dFree(menuItem->text);
  530. dFree(menuItem->accelerator);
  531. delete menuItem;
  532. }
  533. void GuiMenuBar::addMenuItem(Menu *menu, const char *text, U32 id, const char *accelerator, S32 checkGroup)
  534. {
  535. // allocate the new menu item
  536. MenuItem *newMenuItem = new MenuItem;
  537. newMenuItem->text = dStrdup(text);
  538. if(accelerator[0])
  539. newMenuItem->accelerator = dStrdup(accelerator);
  540. else
  541. newMenuItem->accelerator = NULL;
  542. newMenuItem->id = id;
  543. newMenuItem->checkGroup = checkGroup;
  544. newMenuItem->nextMenuItem = NULL;
  545. newMenuItem->acceleratorIndex = 0;
  546. newMenuItem->enabled = text[0] != '-';
  547. newMenuItem->visible = true;
  548. newMenuItem->bitmapIndex = -1;
  549. // DAW: Default to not having a submenu
  550. newMenuItem->isSubmenu = false;
  551. newMenuItem->firstSubmenuItem = NULL;
  552. newMenuItem->submenuParentMenu = NULL;
  553. // link it into the menu's menu item list
  554. MenuItem **walk = &menu->firstMenuItem;
  555. while(*walk)
  556. walk = &(*walk)->nextMenuItem;
  557. *walk = newMenuItem;
  558. }
  559. void GuiMenuBar::clearMenuItems(Menu *menu)
  560. {
  561. while(menu->firstMenuItem)
  562. removeMenuItem(menu, menu->firstMenuItem);
  563. }
  564. void GuiMenuBar::clearMenus()
  565. {
  566. while(menuList)
  567. removeMenu(menuList);
  568. }
  569. //------------------------------------------------------------------------------
  570. // DAW: Submenu methods
  571. //------------------------------------------------------------------------------
  572. // DAW: This method will return the MenuItem class of of a submenu's menu item given
  573. // its parent menu and parent menuitem. If the menuitem ID is used, then the submenu
  574. // ID must also be used.
  575. GuiMenuBar::MenuItem *GuiMenuBar::findSubmenuItem(Menu *menu, const char *menuItem, const char *submenuItem)
  576. {
  577. if(dIsdigit(menuItem[0]))
  578. {
  579. // DAW: Search by ID
  580. U32 id = dAtoi(menuItem);
  581. for(MenuItem *walk = menu->firstMenuItem; walk; walk = walk->nextMenuItem)
  582. if(id == walk->id)
  583. {
  584. if(walk->isSubmenu)
  585. {
  586. U32 subid = dAtoi(submenuItem);
  587. for(MenuItem *subwalk = walk->firstSubmenuItem; subwalk; subwalk = subwalk->nextMenuItem)
  588. {
  589. if(subid == walk->id)
  590. {
  591. return subwalk;
  592. }
  593. }
  594. }
  595. return NULL;
  596. }
  597. return NULL;
  598. }
  599. else
  600. {
  601. // DAW: Search by name
  602. for(MenuItem *walk = menu->firstMenuItem; walk; walk = walk->nextMenuItem)
  603. if(!dStricmp(menuItem, walk->text))
  604. {
  605. if(walk->isSubmenu)
  606. {
  607. for(MenuItem *subwalk = walk->firstSubmenuItem; subwalk; subwalk = subwalk->nextMenuItem)
  608. {
  609. if(!dStricmp(submenuItem, subwalk->text))
  610. return subwalk;
  611. }
  612. }
  613. return NULL;
  614. }
  615. return NULL;
  616. }
  617. }
  618. // DAW: Add a menuitem to the given submenu
  619. void GuiMenuBar::addSubmenuItem(Menu *menu, MenuItem *submenu, const char *text, U32 id, const char *accelerator, S32 checkGroup)
  620. {
  621. // Check that the given menu item supports a submenu
  622. if(submenu && !submenu->isSubmenu)
  623. {
  624. Con::errorf("GuiMenuBar::addSubmenuItem: Attempting to add menuitem '%s' to an invalid submenu",text);
  625. return;
  626. }
  627. // allocate the new menu item
  628. MenuItem *newMenuItem = new MenuItem;
  629. newMenuItem->text = dStrdup(text);
  630. if(accelerator[0])
  631. newMenuItem->accelerator = dStrdup(accelerator);
  632. else
  633. newMenuItem->accelerator = NULL;
  634. newMenuItem->id = id;
  635. newMenuItem->checkGroup = checkGroup;
  636. newMenuItem->nextMenuItem = NULL;
  637. newMenuItem->acceleratorIndex = 0;
  638. newMenuItem->enabled = text[0] != '-';
  639. newMenuItem->visible = true;
  640. newMenuItem->bitmapIndex = -1;
  641. // DAW: Default to not having a submenu
  642. newMenuItem->isSubmenu = false;
  643. newMenuItem->firstSubmenuItem = NULL;
  644. // DAW: Point back to the submenu's menu
  645. newMenuItem->submenuParentMenu = menu;
  646. // link it into the menu's menu item list
  647. MenuItem **walk = &submenu->firstSubmenuItem;
  648. while(*walk)
  649. walk = &(*walk)->nextMenuItem;
  650. *walk = newMenuItem;
  651. }
  652. // DAW: Remove a submenu item
  653. void GuiMenuBar::removeSubmenuItem(MenuItem *menuItem, MenuItem *submenuItem)
  654. {
  655. // Check that the given menu item supports a submenu
  656. if(menuItem && !menuItem->isSubmenu)
  657. {
  658. Con::errorf("GuiMenuBar::removeSubmenuItem: Attempting to remove submenuitem '%s' from an invalid submenu",submenuItem->text);
  659. return;
  660. }
  661. for(MenuItem **subwalk = &menuItem->firstSubmenuItem; *subwalk; subwalk = &(*subwalk)->nextMenuItem)
  662. {
  663. if(*subwalk == submenuItem)
  664. {
  665. *subwalk = submenuItem->nextMenuItem;
  666. break;
  667. }
  668. }
  669. dFree(submenuItem->text);
  670. dFree(submenuItem->accelerator);
  671. delete submenuItem;
  672. }
  673. // DAW: Clear all menuitems from a submenu
  674. void GuiMenuBar::clearSubmenuItems(MenuItem *menuitem)
  675. {
  676. // Check that the given menu item supports a submenu
  677. if(menuitem && !menuitem->isSubmenu)
  678. {
  679. Con::errorf("GuiMenuBar::clearSubmenuItems: Attempting to clear an invalid submenu");
  680. return;
  681. }
  682. while(menuitem->firstSubmenuItem)
  683. removeSubmenuItem(menuitem, menuitem->firstSubmenuItem);
  684. }
  685. //------------------------------------------------------------------------------
  686. // initialization, input and render methods
  687. //------------------------------------------------------------------------------
  688. GuiMenuBar::GuiMenuBar()
  689. {
  690. menuList = NULL;
  691. menuBarDirty = true;
  692. mouseDownMenu = NULL;
  693. mouseOverMenu = NULL;
  694. mCurAcceleratorIndex = 0;
  695. mBackground = NULL;
  696. mPadding = 0;
  697. mCheckmarkBitmapIndex = 0; // Default to the first image in the bitmap array for the check mark
  698. mHorizontalMargin = 6; // Default number of pixels on the left and right side of a manu's text
  699. mVerticalMargin = 1; // Default number of pixels on the top and bottom of a menu's text
  700. mBitmapMargin = 2; // Default number of pixels between a menu's bitmap and text
  701. // DAW: Added:
  702. mouseDownSubmenu = NULL;
  703. mouseOverSubmenu = NULL;
  704. mSubmenuBackground = NULL;
  705. mSubmenuTextList = NULL;
  706. mMouseOverCounter = 0;
  707. mCountMouseOver = false;
  708. mMouseHoverAmount = 30;
  709. setProcessTicks(false);
  710. }
  711. void GuiMenuBar::initPersistFields()
  712. {
  713. Parent::initPersistFields();
  714. addField("Padding", TypeS32, Offset( mPadding, GuiMenuBar ) );
  715. }
  716. bool GuiMenuBar::onWake()
  717. {
  718. if(!Parent::onWake())
  719. return false;
  720. mProfile->constructBitmapArray(); // if a bitmap was specified...
  721. maxBitmapSize.set(0,0);
  722. S32 numBitmaps = mProfile->mBitmapArrayRects.size();
  723. if(numBitmaps)
  724. {
  725. RectI *bitmapBounds = mProfile->mBitmapArrayRects.address();
  726. for(S32 i = 0; i < numBitmaps; i++)
  727. {
  728. if(bitmapBounds[i].extent.x > maxBitmapSize.x)
  729. maxBitmapSize.x = bitmapBounds[i].extent.x;
  730. if(bitmapBounds[i].extent.y > maxBitmapSize.y)
  731. maxBitmapSize.y = bitmapBounds[i].extent.y;
  732. }
  733. }
  734. return true;
  735. }
  736. GuiMenuBar::Menu *GuiMenuBar::findHitMenu(Point2I mousePoint)
  737. {
  738. Point2I pos = globalToLocalCoord(mousePoint);
  739. for(Menu *walk = menuList; walk; walk = walk->nextMenu)
  740. if(walk->visible && walk->bounds.pointInRect(pos))
  741. return walk;
  742. return NULL;
  743. }
  744. void GuiMenuBar::onPreRender()
  745. {
  746. Parent::onPreRender();
  747. if(menuBarDirty)
  748. {
  749. menuBarDirty = false;
  750. U32 curX = mPadding;
  751. for(Menu *walk = menuList; walk; walk = walk->nextMenu)
  752. {
  753. if(!walk->visible)
  754. continue;
  755. // Bounds depends on if there is a bitmap to be drawn or not
  756. if(walk->bitmapIndex == -1)
  757. {
  758. // Text only
  759. walk->bounds.set(curX, 0, mProfile->mFont->getStrWidth(walk->text) + (mHorizontalMargin * 2), mBounds.extent.y - (mVerticalMargin * 2));
  760. } else
  761. {
  762. // Will the bitmap and text be draw?
  763. if(!walk->drawBitmapOnly)
  764. {
  765. // Draw the bitmap and the text
  766. RectI *bitmapBounds = mProfile->mBitmapArrayRects.address();
  767. walk->bounds.set(curX, 0, bitmapBounds[walk->bitmapIndex].extent.x + mProfile->mFont->getStrWidth(walk->text) + (mHorizontalMargin * 2), mBounds.extent.y + (mVerticalMargin * 2));
  768. } else
  769. {
  770. // Only the bitmap will be drawn
  771. RectI *bitmapBounds = mProfile->mBitmapArrayRects.address();
  772. walk->bounds.set(curX, 0, bitmapBounds[walk->bitmapIndex].extent.x + mBitmapMargin + (mHorizontalMargin * 2), mBounds.extent.y + (mVerticalMargin * 2));
  773. }
  774. }
  775. curX += walk->bounds.extent.x;
  776. }
  777. mouseOverMenu = NULL;
  778. mouseDownMenu = NULL;
  779. }
  780. }
  781. void GuiMenuBar::checkMenuMouseMove(const GuiEvent &event)
  782. {
  783. Menu *hit = findHitMenu(event.mousePoint);
  784. if(hit && hit != mouseDownMenu)
  785. {
  786. // gotta close out the current menu...
  787. mTextList->setSelectedCell(Point2I(-1, -1));
  788. closeMenu();
  789. mouseOverMenu = mouseDownMenu = hit;
  790. setUpdate();
  791. onAction();
  792. }
  793. }
  794. void GuiMenuBar::onMouseMove(const GuiEvent &event)
  795. {
  796. Menu *hit = findHitMenu(event.mousePoint);
  797. if(hit != mouseOverMenu)
  798. {
  799. // DAW: If we need to, reset the mouse over menu counter and indicate
  800. // that we should track it.
  801. if(hit)
  802. mMouseOverCounter = 0;
  803. if(!mCountMouseOver)
  804. {
  805. // DAW: We've never started the counter, so start it.
  806. if(hit)
  807. mCountMouseOver = true;
  808. }
  809. mouseOverMenu = hit;
  810. setUpdate();
  811. }
  812. }
  813. void GuiMenuBar::onMouseLeave(const GuiEvent &event)
  814. {
  815. if(mouseOverMenu)
  816. setUpdate();
  817. mouseOverMenu = NULL;
  818. // DAW: As we've left the control, don't track how long the mouse has been
  819. // within it.
  820. if(mCountMouseOver && mMouseOverCounter >= mMouseHoverAmount)
  821. {
  822. Con::executef( this, 3, "onMouseInMenu", "0"); // Last parameter indicates if we've entered or left the menu
  823. }
  824. mCountMouseOver = false;
  825. mMouseOverCounter = 0;
  826. }
  827. void GuiMenuBar::onMouseDragged(const GuiEvent &event)
  828. {
  829. Menu *hit = findHitMenu(event.mousePoint);
  830. if(hit != mouseOverMenu)
  831. {
  832. // DAW: If we need to, reset the mouse over menu counter and indicate
  833. // that we should track it.
  834. if(hit)
  835. mMouseOverCounter = 0;
  836. if(!mCountMouseOver)
  837. {
  838. // DAW: We've never started the counter, so start it.
  839. if(hit)
  840. mCountMouseOver = true;
  841. }
  842. mouseOverMenu = hit;
  843. mouseDownMenu = hit;
  844. setUpdate();
  845. onAction();
  846. }
  847. }
  848. void GuiMenuBar::onMouseDown(const GuiEvent &event)
  849. {
  850. mouseDownMenu = mouseOverMenu = findHitMenu(event.mousePoint);
  851. setUpdate();
  852. onAction();
  853. }
  854. void GuiMenuBar::onMouseUp(const GuiEvent &event)
  855. {
  856. mouseDownMenu = NULL;
  857. setUpdate();
  858. }
  859. void GuiMenuBar::onRender(Point2I offset, const RectI &updateRect)
  860. {
  861. RectI ctrlRect(offset, mBounds.extent);
  862. //if opaque, fill the update rect with the fill color
  863. if (mProfile->mOpaque)
  864. dglDrawRectFill(RectI(offset, mBounds.extent), mProfile->mFillColor);
  865. //if there's a border, draw the border
  866. if (mProfile->mBorder)
  867. renderBorder(ctrlRect, mProfile);
  868. for(Menu *walk = menuList; walk; walk = walk->nextMenu)
  869. {
  870. if(!walk->visible)
  871. continue;
  872. ColorI fontColor = mProfile->mFontColor;
  873. RectI bounds = walk->bounds;
  874. bounds.point += offset;
  875. Point2I start;
  876. start.x = walk->bounds.point.x + mHorizontalMargin;
  877. start.y = walk->bounds.point.y + ( walk->bounds.extent.y - mProfile->mFont->getHeight() ) / 2;
  878. // Draw the border
  879. if(walk->drawBorder)
  880. {
  881. RectI highlightBounds = bounds;
  882. highlightBounds.inset(1,1);
  883. if(walk == mouseDownMenu)
  884. renderFilledBorder(highlightBounds, mProfile->mBorderColorHL, mProfile->mFillColorHL );
  885. else if(walk == mouseOverMenu && mouseDownMenu == NULL)
  886. renderFilledBorder(highlightBounds, mProfile->mBorderColor, mProfile->mFillColor );
  887. }
  888. // Do we draw a bitmap?
  889. if(walk->bitmapIndex != -1)
  890. {
  891. S32 index = walk->bitmapIndex * 3;
  892. if(walk == mouseDownMenu)
  893. ++index;
  894. else if(walk == mouseOverMenu && mouseDownMenu == NULL)
  895. index += 2;
  896. RectI rect = mProfile->mBitmapArrayRects[index];
  897. Point2I bitmapstart(start);
  898. bitmapstart.y = walk->bounds.point.y + ( walk->bounds.extent.y - rect.extent.y ) / 2;
  899. dglClearBitmapModulation();
  900. dglDrawBitmapSR(mProfile->mTextureHandle, offset + bitmapstart, rect);
  901. // Should we also draw the text?
  902. if(!walk->drawBitmapOnly)
  903. {
  904. start.x += mBitmapMargin;
  905. dglSetBitmapModulation( fontColor );
  906. dglDrawText( mProfile->mFont, start + offset, walk->text, mProfile->mFontColors );
  907. }
  908. } else
  909. {
  910. dglSetBitmapModulation( fontColor );
  911. dglDrawText( mProfile->mFont, start + offset, walk->text, mProfile->mFontColors );
  912. }
  913. }
  914. renderChildControls( offset, updateRect );
  915. }
  916. void GuiMenuBar::buildAcceleratorMap()
  917. {
  918. Parent::buildAcceleratorMap();
  919. // ok, accelerator map is cleared...
  920. // add all our keys:
  921. mCurAcceleratorIndex = 1;
  922. for(Menu *menu = menuList; menu; menu = menu->nextMenu)
  923. {
  924. for(MenuItem *item = menu->firstMenuItem; item; item = item->nextMenuItem)
  925. {
  926. if(!item->accelerator)
  927. {
  928. item->accelerator = 0;
  929. continue;
  930. }
  931. EventDescriptor accelEvent;
  932. ActionMap::createEventDescriptor(item->accelerator, &accelEvent);
  933. //now we have a modifier, and a key, add them to the canvas
  934. GuiCanvas *root = getRoot();
  935. if (root)
  936. root->addAcceleratorKey(this, mCurAcceleratorIndex, accelEvent.eventCode, accelEvent.flags);
  937. item->acceleratorIndex = mCurAcceleratorIndex;
  938. mCurAcceleratorIndex++;
  939. }
  940. }
  941. }
  942. void GuiMenuBar::acceleratorKeyPress(U32 index)
  943. {
  944. // loop through all the menus
  945. // and find the item that corresponds to the accelerator index
  946. for(Menu *menu = menuList; menu; menu = menu->nextMenu)
  947. {
  948. if(!menu->visible)
  949. continue;
  950. for(MenuItem *item = menu->firstMenuItem; item; item = item->nextMenuItem)
  951. {
  952. if(item->acceleratorIndex == index)
  953. {
  954. // first, call the script callback for menu selection:
  955. Con::executef( this, 4, "onMenuSelect", Con::getIntArg(menu->id),
  956. menu->text);
  957. if(item->visible)
  958. menuItemSelected(menu, item);
  959. return;
  960. }
  961. }
  962. }
  963. }
  964. //------------------------------------------------------------------------------
  965. // Menu display class methods
  966. //------------------------------------------------------------------------------
  967. GuiMenuBackgroundCtrl::GuiMenuBackgroundCtrl(GuiMenuBar *ctrl, GuiMenuTextListCtrl *textList)
  968. {
  969. mMenuBarCtrl = ctrl;
  970. mTextList = textList;
  971. }
  972. void GuiMenuBackgroundCtrl::onMouseDown(const GuiEvent &event)
  973. {
  974. mTextList->setSelectedCell(Point2I(-1,-1));
  975. mMenuBarCtrl->closeMenu();
  976. }
  977. void GuiMenuBackgroundCtrl::onMouseMove(const GuiEvent &event)
  978. {
  979. GuiCanvas *root = getRoot();
  980. GuiControl *ctrlHit = root->findHitControl(event.mousePoint, mLayer - 1);
  981. if(ctrlHit == mMenuBarCtrl) // see if the current mouse over menu is right...
  982. mMenuBarCtrl->checkMenuMouseMove(event);
  983. }
  984. void GuiMenuBackgroundCtrl::onMouseDragged(const GuiEvent &event)
  985. {
  986. GuiCanvas *root = getRoot();
  987. GuiControl *ctrlHit = root->findHitControl(event.mousePoint, mLayer - 1);
  988. if(ctrlHit == mMenuBarCtrl) // see if the current mouse over menu is right...
  989. mMenuBarCtrl->checkMenuMouseMove(event);
  990. }
  991. GuiMenuTextListCtrl::GuiMenuTextListCtrl(GuiMenuBar *ctrl)
  992. {
  993. mMenuBarCtrl = ctrl;
  994. isSubMenu = false; // DAW: Added
  995. }
  996. void GuiMenuTextListCtrl::onRenderCell(Point2I offset, Point2I cell, bool selected, bool mouseOver)
  997. {
  998. if(dStrcmp(mList[cell.y].text + 3, "-\t")) // DAW: Was: dStrcmp(mList[cell.y].text + 2, "-\t")) but has been changed to take into account the submenu flag
  999. Parent::onRenderCell(offset, cell, selected, mouseOver);
  1000. else
  1001. {
  1002. S32 yp = offset.y + mCellSize.y / 2;
  1003. dglDrawLine(offset.x, yp, offset.x + mCellSize.x, yp, ColorI(128,128,128));
  1004. dglDrawLine(offset.x, yp+1, offset.x + mCellSize.x, yp+1, ColorI(255,255,255));
  1005. }
  1006. // now see if there's a bitmap...
  1007. U8 idx = mList[cell.y].text[0];
  1008. if(idx != 1)
  1009. {
  1010. // there's a bitmap...
  1011. U32 index = U32(idx - 2) * 3;
  1012. if(!mList[cell.y].active)
  1013. index += 2;
  1014. else if(selected || mouseOver)
  1015. index ++;
  1016. RectI rect = mProfile->mBitmapArrayRects[index];
  1017. Point2I off = mMenuBarCtrl->maxBitmapSize - rect.extent;
  1018. off /= 2;
  1019. dglClearBitmapModulation();
  1020. dglDrawBitmapSR(mProfile->mTextureHandle, offset + off, rect);
  1021. }
  1022. // DAW: Check if this is a submenu
  1023. idx = mList[cell.y].text[1];
  1024. if(idx != 1)
  1025. {
  1026. #if defined(TORQUE_OS_IOS) || defined(TORQUE_OS_ANDROID) || defined(TORQUE_OS_EMSCRIPTEN)
  1027. // PUAP -Mat untested
  1028. //How are these used/made? cannot create in TGB GUI editor
  1029. if(selected || mouseOver)
  1030. {
  1031. glColor4f(mProfile->mFontColorHL.red,mProfile->mFontColorHL.green,mProfile->mFontColorHL.blue, 255 );//full alpha
  1032. }
  1033. else
  1034. {
  1035. glColor4f(mProfile->mFontColor.red,mProfile->mFontColor.green,mProfile->mFontColor.blue, 255);
  1036. }
  1037. glDrawArrays(GL_TRIANGLES, 0, 3 );
  1038. #else
  1039. // This is a submenu, so draw an arrow
  1040. F32 left = (F32)(offset.x + mCellSize.x - 12);
  1041. F32 right = (F32)(left + 8);
  1042. F32 top = (F32)(mCellSize.y / 2 + offset.y - 4);
  1043. F32 bottom = (F32)(top + 8);
  1044. F32 middle = (F32)(top + 4);
  1045. glBegin(GL_TRIANGLES);
  1046. if(selected || mouseOver)
  1047. {
  1048. glColor3ub(mProfile->mFontColorHL.red,mProfile->mFontColorHL.green,mProfile->mFontColorHL.blue);
  1049. } else
  1050. {
  1051. glColor3ub(mProfile->mFontColor.red,mProfile->mFontColor.green,mProfile->mFontColor.blue);
  1052. }
  1053. glVertex2fv( Point3F(left, top, 0.0f) );
  1054. glVertex2fv( Point3F(right, middle, 0.0f) );
  1055. glVertex2fv( Point3F(left, bottom, 0.0f) );
  1056. glEnd();
  1057. #endif
  1058. }
  1059. }
  1060. bool GuiMenuTextListCtrl::onKeyDown(const GuiEvent &event)
  1061. {
  1062. //if the control is a dead end, don't process the input:
  1063. if ( !mVisible || !mActive || !mAwake )
  1064. return false;
  1065. //see if the key down is a <return> or not
  1066. if ( event.modifier == 0 )
  1067. {
  1068. if ( event.keyCode == KEY_RETURN )
  1069. {
  1070. mMenuBarCtrl->closeMenu();
  1071. return true;
  1072. }
  1073. else if ( event.keyCode == KEY_ESCAPE )
  1074. {
  1075. mSelectedCell.set( -1, -1 );
  1076. mMenuBarCtrl->closeMenu();
  1077. return true;
  1078. }
  1079. }
  1080. //otherwise, pass the event to it's parent
  1081. return Parent::onKeyDown(event);
  1082. }
  1083. void GuiMenuTextListCtrl::onMouseDown(const GuiEvent &event)
  1084. {
  1085. Parent::onMouseDown(event);
  1086. mMenuBarCtrl->closeMenu();
  1087. }
  1088. void GuiMenuTextListCtrl::onMouseUp(const GuiEvent &event)
  1089. {
  1090. // ok, this is kind of strange... but!
  1091. // here's the deal: if we get a mouse up in this control
  1092. // it means the mouse was dragged from the initial menu mouse click
  1093. // so: activate the menu result as though this event were,
  1094. // instead, a mouse down.
  1095. onMouseDown(event);
  1096. }
  1097. void GuiMenuTextListCtrl::onCellHighlighted(Point2I cell)
  1098. {
  1099. // If this text list control is part of a submenu, then don't worry about
  1100. // passing this along
  1101. if(!isSubMenu)
  1102. {
  1103. RectI globalbounds(mBounds);
  1104. Point2I globalpoint = localToGlobalCoord(globalbounds.point);
  1105. globalbounds.point = globalpoint;
  1106. mMenuBarCtrl->highlightedMenuItem(cell.y, globalbounds, mCellSize);
  1107. }
  1108. }
  1109. //------------------------------------------------------------------------------
  1110. // Submenu display class methods
  1111. //------------------------------------------------------------------------------
  1112. GuiSubmenuBackgroundCtrl::GuiSubmenuBackgroundCtrl(GuiMenuBar *ctrl, GuiMenuTextListCtrl *textList) : GuiMenuBackgroundCtrl(ctrl, textList)
  1113. {
  1114. }
  1115. void GuiSubmenuBackgroundCtrl::onMouseDown(const GuiEvent &event)
  1116. {
  1117. mTextList->setSelectedCell(Point2I(-1,-1));
  1118. mMenuBarCtrl->closeMenu();
  1119. }
  1120. bool GuiSubmenuBackgroundCtrl::pointInControl(const Point2I& parentCoordPoint)
  1121. {
  1122. S32 xt = parentCoordPoint.x - mBounds.point.x;
  1123. S32 yt = parentCoordPoint.y - mBounds.point.y;
  1124. if(findHitControl(Point2I(xt,yt)) == this)
  1125. return false;
  1126. else
  1127. return true;
  1128. // return xt >= 0 && yt >= 0 && xt < mBounds.extent.x && yt < mBounds.extent.y;
  1129. }
  1130. //------------------------------------------------------------------------------
  1131. void GuiMenuBar::menuItemSelected(GuiMenuBar::Menu *menu, GuiMenuBar::MenuItem *item)
  1132. {
  1133. if(item->enabled)
  1134. Con::executef( this, 6, "onMenuItemSelect", Con::getIntArg(menu->id),
  1135. menu->text, Con::getIntArg(item->id), item->text);
  1136. }
  1137. void GuiMenuBar::onSleep()
  1138. {
  1139. if(mBackground) // a menu is up?
  1140. {
  1141. mTextList->setSelectedCell(Point2I(-1, -1));
  1142. closeMenu();
  1143. }
  1144. Parent::onSleep();
  1145. }
  1146. void GuiMenuBar::closeMenu()
  1147. {
  1148. // DAW: First close any open submenu
  1149. closeSubmenu();
  1150. // Get the selection from the text list:
  1151. S32 selectionIndex = mTextList->getSelectedCell().y;
  1152. // Pop the background:
  1153. if( getRoot() )
  1154. getRoot()->popDialogControl(mBackground);
  1155. else
  1156. return;
  1157. // Kill the popup:
  1158. mBackground->deleteObject();
  1159. mBackground = NULL;
  1160. // Now perform the popup action:
  1161. if ( selectionIndex != -1 )
  1162. {
  1163. MenuItem *list = mouseDownMenu->firstMenuItem;
  1164. while(selectionIndex && list)
  1165. {
  1166. list = list->nextMenuItem;
  1167. selectionIndex--;
  1168. }
  1169. if(list)
  1170. menuItemSelected(mouseDownMenu, list);
  1171. }
  1172. mouseDownMenu = NULL;
  1173. }
  1174. // DAW: Called when a menu item is highlighted by the mouse
  1175. void GuiMenuBar::highlightedMenuItem(S32 selectionIndex, RectI bounds, Point2I cellSize)
  1176. {
  1177. S32 selstore = selectionIndex;
  1178. // Now perform the popup action:
  1179. if ( selectionIndex != -1 )
  1180. {
  1181. MenuItem *list = mouseDownMenu->firstMenuItem;
  1182. while(selectionIndex && list)
  1183. {
  1184. list = list->nextMenuItem;
  1185. selectionIndex--;
  1186. }
  1187. if(list)
  1188. {
  1189. // If the highlighted item has changed...
  1190. if(mouseOverSubmenu != list)
  1191. {
  1192. closeSubmenu();
  1193. mouseOverSubmenu = NULL;
  1194. // Check if this is a submenu. If so, open the submenu.
  1195. if(list->isSubmenu)
  1196. {
  1197. // If there are submenu items, then open the submenu
  1198. if(list->firstSubmenuItem)
  1199. {
  1200. mouseOverSubmenu = list;
  1201. onSubmenuAction(selstore, bounds, cellSize);
  1202. }
  1203. }
  1204. }
  1205. }
  1206. }
  1207. }
  1208. //------------------------------------------------------------------------------
  1209. void GuiMenuBar::onAction()
  1210. {
  1211. if(!mouseDownMenu)
  1212. return;
  1213. // first, call the script callback for menu selection:
  1214. Con::executef( this, 4, "onMenuSelect", Con::getIntArg(mouseDownMenu->id),
  1215. mouseDownMenu->text);
  1216. MenuItem *visWalk = mouseDownMenu->firstMenuItem;
  1217. while(visWalk)
  1218. {
  1219. if(visWalk->visible)
  1220. break;
  1221. visWalk = visWalk->nextMenuItem;
  1222. }
  1223. if(!visWalk)
  1224. {
  1225. mouseDownMenu = NULL;
  1226. return;
  1227. }
  1228. mTextList = new GuiMenuTextListCtrl(this);
  1229. mTextList->mProfile = mProfile;
  1230. mBackground = new GuiMenuBackgroundCtrl(this, mTextList);
  1231. GuiCanvas *root = getRoot();
  1232. Point2I windowExt = root->mBounds.extent;
  1233. mBackground->mBounds.point.set(0,0);
  1234. mBackground->mBounds.extent = root->mBounds.extent;
  1235. S32 textWidth = 0, width = 0;
  1236. S32 acceleratorWidth = 0;
  1237. GFont *font = mProfile->mFont;
  1238. for(MenuItem *walk = mouseDownMenu->firstMenuItem; walk; walk = walk->nextMenuItem)
  1239. {
  1240. if(!walk->visible)
  1241. continue;
  1242. S32 iTextWidth = font->getStrWidth(walk->text);
  1243. S32 iAcceleratorWidth = walk->accelerator ? font->getStrWidth(walk->accelerator) : 0;
  1244. if(iTextWidth > textWidth)
  1245. textWidth = iTextWidth;
  1246. if(iAcceleratorWidth > acceleratorWidth)
  1247. acceleratorWidth = iAcceleratorWidth;
  1248. }
  1249. width = textWidth + acceleratorWidth + maxBitmapSize.x * 2 + 2 + 4;
  1250. mTextList->setCellSize(Point2I(width, font->getHeight()+2));
  1251. mTextList->clearColumnOffsets();
  1252. mTextList->addColumnOffset(-1); // add an empty column in for the bitmap index.
  1253. mTextList->addColumnOffset(maxBitmapSize.x + 1);
  1254. mTextList->addColumnOffset(maxBitmapSize.x + 1 + textWidth + 4);
  1255. U32 entryCount = 0;
  1256. for(MenuItem *walk = mouseDownMenu->firstMenuItem; walk; walk = walk->nextMenuItem)
  1257. {
  1258. if(!walk->visible)
  1259. continue;
  1260. char buf[512];
  1261. // DAW: If this menu item is a submenu, then set the isSubmenu to 2 to indicate
  1262. // an arrow should be drawn. Otherwise set the isSubmenu normally.
  1263. char isSubmenu = 1;
  1264. if(walk->isSubmenu)
  1265. isSubmenu = 2;
  1266. char bitmapIndex = 1;
  1267. if(walk->bitmapIndex >= 0 && (walk->bitmapIndex * 3 <= mProfile->mBitmapArrayRects.size()))
  1268. bitmapIndex = walk->bitmapIndex + 2;
  1269. dSprintf(buf, sizeof(buf), "%c%c\t%s\t%s", bitmapIndex, isSubmenu, walk->text, walk->accelerator ? walk->accelerator : "");
  1270. mTextList->addEntry(entryCount, buf);
  1271. if(!walk->enabled)
  1272. mTextList->setEntryActive(entryCount, false);
  1273. entryCount++;
  1274. }
  1275. Point2I menuPoint = localToGlobalCoord(mouseDownMenu->bounds.point);
  1276. menuPoint.y += mouseDownMenu->bounds.extent.y; // DAW: Used to have this at the end: + 2;
  1277. GuiControl *ctrl = new GuiControl;
  1278. ctrl->mBounds.point = menuPoint;
  1279. ctrl->mBounds.extent = mTextList->mBounds.extent + Point2I(6, 6);
  1280. ctrl->mProfile = mProfile;
  1281. mTextList->mBounds.point += Point2I(3,3);
  1282. // DAW: Make sure the menu doesn't go beyond the Canvas' bottom edge.
  1283. if((ctrl->mBounds.point.y+ctrl->mBounds.extent.y) > windowExt.y)
  1284. {
  1285. // DAW: Pop the menu above the menu bar
  1286. Point2I menuBar = localToGlobalCoord(mouseDownMenu->bounds.point);
  1287. ctrl->mBounds.point.y = menuBar.y - ctrl->mBounds.extent.y;
  1288. }
  1289. //mTextList->mBounds.point = Point2I(3,3);
  1290. mTextList->registerObject();
  1291. mBackground->registerObject();
  1292. ctrl->registerObject();
  1293. mBackground->addObject( ctrl );
  1294. ctrl->addObject( mTextList );
  1295. root->pushDialogControl(mBackground, mLayer + 1);
  1296. mTextList->setFirstResponder();
  1297. }
  1298. //------------------------------------------------------------------------------
  1299. // DAW: Performs an action when a menu item that is a submenu is selected/highlighted
  1300. void GuiMenuBar::onSubmenuAction(S32 selectionIndex, RectI bounds, Point2I cellSize)
  1301. {
  1302. if(!mouseOverSubmenu)
  1303. return;
  1304. // first, call the script callback for menu selection:
  1305. Con::executef( this, 4, "onSubmenuSelect", Con::getIntArg(mouseOverSubmenu->id),
  1306. mouseOverSubmenu->text);
  1307. MenuItem *visWalk = mouseOverSubmenu->firstSubmenuItem;
  1308. while(visWalk)
  1309. {
  1310. if(visWalk->visible)
  1311. break;
  1312. visWalk = visWalk->nextMenuItem;
  1313. }
  1314. if(!visWalk)
  1315. {
  1316. mouseOverSubmenu = NULL;
  1317. return;
  1318. }
  1319. mSubmenuTextList = new GuiMenuTextListCtrl(this);
  1320. mSubmenuTextList->mProfile = mProfile;
  1321. mSubmenuTextList->isSubMenu = true; // Indicate that this text list is part of a submenu
  1322. mSubmenuBackground = new GuiSubmenuBackgroundCtrl(this, mSubmenuTextList);
  1323. GuiCanvas *root = getRoot();
  1324. Point2I windowExt = root->mBounds.extent;
  1325. mSubmenuBackground->mBounds.point.set(0,0);
  1326. mSubmenuBackground->mBounds.extent = root->mBounds.extent;
  1327. S32 textWidth = 0, width = 0;
  1328. S32 acceleratorWidth = 0;
  1329. GFont *font = mProfile->mFont;
  1330. for(MenuItem *walk = mouseOverSubmenu->firstSubmenuItem; walk; walk = walk->nextMenuItem)
  1331. {
  1332. if(!walk->visible)
  1333. continue;
  1334. S32 iTextWidth = font->getStrWidth(walk->text);
  1335. S32 iAcceleratorWidth = walk->accelerator ? font->getStrWidth(walk->accelerator) : 0;
  1336. if(iTextWidth > textWidth)
  1337. textWidth = iTextWidth;
  1338. if(iAcceleratorWidth > acceleratorWidth)
  1339. acceleratorWidth = iAcceleratorWidth;
  1340. }
  1341. width = textWidth + acceleratorWidth + maxBitmapSize.x * 2 + 2 + 4;
  1342. mSubmenuTextList->setCellSize(Point2I(width, font->getHeight()+3));
  1343. mSubmenuTextList->clearColumnOffsets();
  1344. mSubmenuTextList->addColumnOffset(-1); // add an empty column in for the bitmap index.
  1345. mSubmenuTextList->addColumnOffset(maxBitmapSize.x + 1);
  1346. mSubmenuTextList->addColumnOffset(maxBitmapSize.x + 1 + textWidth + 4);
  1347. U32 entryCount = 0;
  1348. for(MenuItem *walk = mouseOverSubmenu->firstSubmenuItem; walk; walk = walk->nextMenuItem)
  1349. {
  1350. if(!walk->visible)
  1351. continue;
  1352. char buf[512];
  1353. // DAW: Can't have submenus within submenus.
  1354. char isSubmenu = 1;
  1355. char bitmapIndex = 1;
  1356. if(walk->bitmapIndex >= 0 && (walk->bitmapIndex * 3 <= mProfile->mBitmapArrayRects.size()))
  1357. bitmapIndex = walk->bitmapIndex + 2;
  1358. dSprintf(buf, sizeof(buf), "%c%c\t%s\t%s", bitmapIndex, isSubmenu, walk->text, walk->accelerator ? walk->accelerator : "");
  1359. mSubmenuTextList->addEntry(entryCount, buf);
  1360. if(!walk->enabled)
  1361. mSubmenuTextList->setEntryActive(entryCount, false);
  1362. entryCount++;
  1363. }
  1364. Point2I menuPoint = bounds.point; //localToGlobalCoord(bounds.point);
  1365. menuPoint.x += bounds.extent.x;
  1366. menuPoint.y += cellSize.y * selectionIndex - 6;
  1367. GuiControl *ctrl = new GuiControl;
  1368. ctrl->mBounds.point = menuPoint;
  1369. ctrl->mBounds.extent = mSubmenuTextList->mBounds.extent + Point2I(6, 6);
  1370. ctrl->mProfile = mProfile;
  1371. mSubmenuTextList->mBounds.point += Point2I(3,3);
  1372. // DAW: Make sure the menu doesn't go beyond the Canvas' bottom edge.
  1373. if((ctrl->mBounds.point.y+ctrl->mBounds.extent.y) > windowExt.y)
  1374. {
  1375. // DAW: Pop the menu above the menu bar
  1376. ctrl->mBounds.point.y -= mSubmenuTextList->mBounds.extent.y - cellSize.y - 6 - 3;
  1377. }
  1378. // DAW: And the same for the right edge
  1379. if((ctrl->mBounds.point.x+ctrl->mBounds.extent.x) > windowExt.x)
  1380. {
  1381. // DAW: Pop the submenu to the left of the menu
  1382. ctrl->mBounds.point.x -= mSubmenuTextList->mBounds.extent.x + cellSize.x + 6;
  1383. }
  1384. //mSubmenuTextList->mBounds.point = Point2I(3,3);
  1385. mSubmenuTextList->registerObject();
  1386. mSubmenuBackground->registerObject();
  1387. ctrl->registerObject();
  1388. mSubmenuBackground->addObject( ctrl );
  1389. ctrl->addObject( mSubmenuTextList );
  1390. root->pushDialogControl(mSubmenuBackground, mLayer + 1);
  1391. mSubmenuTextList->setFirstResponder();
  1392. }
  1393. // DAW: Close down the submenu controls
  1394. void GuiMenuBar::closeSubmenu()
  1395. {
  1396. if(!mSubmenuBackground || !mSubmenuTextList)
  1397. return;
  1398. // Get the selection from the text list:
  1399. S32 selectionIndex = mSubmenuTextList->getSelectedCell().y;
  1400. // Pop the background:
  1401. if( getRoot() )
  1402. getRoot()->popDialogControl(mSubmenuBackground);
  1403. // Kill the popup:
  1404. mSubmenuBackground->deleteObject();
  1405. mSubmenuBackground = NULL;
  1406. mSubmenuTextList = NULL;
  1407. // Now perform the popup action:
  1408. if ( selectionIndex != -1 )
  1409. {
  1410. MenuItem *list = NULL;
  1411. if(mouseOverSubmenu)
  1412. {
  1413. list = mouseOverSubmenu->firstSubmenuItem;
  1414. while(selectionIndex && list)
  1415. {
  1416. list = list->nextMenuItem;
  1417. selectionIndex--;
  1418. }
  1419. }
  1420. if(list)
  1421. menuItemSelected(list->submenuParentMenu, list);
  1422. }
  1423. mouseOverSubmenu = NULL;
  1424. }
  1425. // DAW: Find if the mouse pointer is within a menu item
  1426. GuiMenuBar::MenuItem *GuiMenuBar::findHitMenuItem(Point2I mousePoint)
  1427. {
  1428. //Point2I pos = globalToLocalCoord(mousePoint);
  1429. // for(Menu *walk = menuList; walk; walk = walk->nextMenu)
  1430. // if(walk->visible && walk->bounds.pointInRect(pos))
  1431. // return walk;
  1432. return NULL;
  1433. }
  1434. // DAW: Checks if the mouse has been moved to a new menu item
  1435. void GuiMenuBar::checkSubmenuMouseMove(const GuiEvent &event)
  1436. {
  1437. MenuItem *hit = findHitMenuItem(event.mousePoint);
  1438. if(hit && hit != mouseOverSubmenu)
  1439. {
  1440. // gotta close out the current menu...
  1441. mSubmenuTextList->setSelectedCell(Point2I(-1, -1));
  1442. // closeSubmenu();
  1443. setUpdate();
  1444. }
  1445. }
  1446. // DAW: Process a tick
  1447. void GuiMenuBar::processTick()
  1448. {
  1449. // If we are to track a tick, then do so.
  1450. if(mCountMouseOver)
  1451. {
  1452. // DAW: If we're at a particular number of ticks, notify the script function
  1453. if(mMouseOverCounter < mMouseHoverAmount)
  1454. {
  1455. ++mMouseOverCounter;
  1456. } else if(mMouseOverCounter == mMouseHoverAmount)
  1457. {
  1458. ++mMouseOverCounter;
  1459. Con::executef( this, 3, "onMouseInMenu", "1"); // Last parameter indicates if we've entered or left the menu
  1460. }
  1461. }
  1462. }