popupMenuSDL.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  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. #ifdef TORQUE_SDL
  23. #include "platform/menus/popupMenu.h"
  24. #include "platform/menus/menuBar.h"
  25. #include "console/consoleTypes.h"
  26. #include "gui/core/guiCanvas.h"
  27. #include "core/util/safeDelete.h"
  28. #include "sim/actionMap.h"
  29. #include "platform/platformInput.h"
  30. #include "windowManager/sdl/sdlWindow.h"
  31. #include "gui/editor/guiMenuBar.h"
  32. #include "platformSDL/menus/PlatformSDLPopupMenuData.h"
  33. #include "console/engineAPI.h"
  34. #include "platformSDL/menus/guiPlatformGenericMenuBar.h"
  35. #include "gui/editor/guiPopupMenuCtrl.h"
  36. //////////////////////////////////////////////////////////////////////////
  37. // Platform Menu Data
  38. //////////////////////////////////////////////////////////////////////////
  39. GuiPlatformGenericMenuBar* findMenuBarCtrl()
  40. {
  41. GuiControl* control;
  42. Sim::findObject("PlatformGenericMenubar", control);
  43. AssertFatal(control, "");
  44. if (!control)
  45. return NULL;
  46. GuiPlatformGenericMenuBar* menuBar;
  47. menuBar = dynamic_cast<GuiPlatformGenericMenuBar*>(control->findObjectByInternalName(StringTable->insert("menubar"), true));
  48. AssertFatal(menuBar, "");
  49. return menuBar;
  50. }
  51. //////////////////////////////////////////////////////////////////////////
  52. void PlatformPopupMenuData::insertAccelerator(EventDescriptor &desc, U32 id)
  53. {
  54. AssertFatal(0, "");
  55. }
  56. void PlatformPopupMenuData::removeAccelerator(U32 id)
  57. {
  58. AssertFatal(0, "");
  59. }
  60. void PlatformPopupMenuData::setAccelleratorEnabled( U32 id, bool enabled )
  61. {
  62. AssertFatal(0, "");
  63. }
  64. //////////////////////////////////////////////////////////////////////////
  65. void PopupMenu::createPlatformPopupMenuData()
  66. {
  67. mData = new PlatformPopupMenuData;
  68. }
  69. void PopupMenu::deletePlatformPopupMenuData()
  70. {
  71. SAFE_DELETE(mData);
  72. }
  73. void PopupMenu::createPlatformMenu()
  74. {
  75. mData->mMenuGui = GuiMenuBar::sCreateMenu( getBarTitle(), getId() );
  76. PlatformPopupMenuData::mMenuMap[ mData->mMenuGui ] = this;
  77. }
  78. //////////////////////////////////////////////////////////////////////////
  79. // Public Methods
  80. //////////////////////////////////////////////////////////////////////////
  81. S32 PopupMenu::insertItem(S32 pos, const char *title, const char* accelerator, const char* cmd)
  82. {
  83. GuiMenuBar::MenuItem *item = GuiMenuBar::findMenuItem( mData->mMenuGui, title );
  84. //We'll make a special exception for the spacer items
  85. if(item && dStrcmp(title, ""))
  86. {
  87. setItem( pos, title, accelerator, cmd);
  88. return pos;
  89. }
  90. item = GuiMenuBar::addMenuItem( mData->mMenuGui, title, pos, accelerator, -1, cmd );
  91. item->submenuParentMenu = this->mData->mMenuGui;
  92. return pos;
  93. }
  94. S32 PopupMenu::insertSubMenu(S32 pos, const char *title, PopupMenu *submenu)
  95. {
  96. GuiMenuBar::MenuItem *item = GuiMenuBar::addMenuItem( mData->mMenuGui, title, pos, "", -1, "" );
  97. item->isSubmenu = true;
  98. item->submenu = submenu->mData->mMenuGui;
  99. item->submenuParentMenu = this->mData->mMenuGui;
  100. return pos;
  101. }
  102. bool PopupMenu::setItem(S32 pos, const char *title, const char* accelerator, const char* cmd)
  103. {
  104. GuiMenuBar::MenuItem *item = NULL;
  105. item = GuiMenuBar::findMenuItem( mData->mMenuGui, title );
  106. if(item)
  107. {
  108. item->id = pos;
  109. item->cmd = cmd;
  110. if( accelerator && accelerator[0] )
  111. item->accelerator = dStrdup( accelerator );
  112. else
  113. item->accelerator = NULL;
  114. return true;
  115. }
  116. return false;
  117. }
  118. void PopupMenu::removeItem(S32 itemPos)
  119. {
  120. GuiMenuBar::MenuItem *item = GuiMenuBar::findMenuItem( mData->mMenuGui, String::ToString(itemPos) );
  121. if(item)
  122. {
  123. GuiMenuBar::removeMenuItem( mData->mMenuGui, item);
  124. }
  125. }
  126. //////////////////////////////////////////////////////////////////////////
  127. void PopupMenu::enableItem( S32 pos, bool enable )
  128. {
  129. GuiMenuBar::MenuItem *item = NULL;
  130. for( item = mData->mMenuGui->firstMenuItem; item; item = item->nextMenuItem )
  131. {
  132. if( item->id == pos)
  133. item->enabled = enable;
  134. }
  135. }
  136. void PopupMenu::checkItem(S32 pos, bool checked)
  137. {
  138. GuiMenuBar::MenuItem *item = NULL;
  139. for( item = mData->mMenuGui->firstMenuItem; item; item = item->nextMenuItem )
  140. if(item->id == pos)
  141. break;
  142. if( !item )
  143. return;
  144. if(checked && item->checkGroup != -1)
  145. {
  146. // first, uncheck everything in the group:
  147. for( GuiMenuBar::MenuItem *itemWalk = mData->mMenuGui->firstMenuItem; itemWalk; itemWalk = itemWalk->nextMenuItem )
  148. if( itemWalk->checkGroup == item->checkGroup && itemWalk->bitmapIndex == mData->mCheckedBitmapIdx )
  149. itemWalk->bitmapIndex = -1;
  150. }
  151. item->bitmapIndex = checked ? mData->mCheckedBitmapIdx : -1;
  152. }
  153. void PopupMenu::checkRadioItem(S32 firstPos, S32 lastPos, S32 checkPos)
  154. {
  155. GuiMenuBar::MenuItem *item = NULL;
  156. for( item = mData->mMenuGui->firstMenuItem; item; item = item->nextMenuItem )
  157. {
  158. if(item->id >= firstPos && item->id <= lastPos)
  159. {
  160. item->bitmapIndex = (item->id == checkPos) ? mData->mCheckedBitmapIdx : -1;
  161. }
  162. }
  163. }
  164. bool PopupMenu::isItemChecked(S32 pos)
  165. {
  166. GuiMenuBar::MenuItem *item = NULL;
  167. for( item = mData->mMenuGui->firstMenuItem; item; item = item->nextMenuItem )
  168. if(item->id == pos)
  169. return item->bitmapIndex == mData->mCheckedBitmapIdx;
  170. return false;
  171. }
  172. U32 PopupMenu::getItemCount()
  173. {
  174. int count = 0;
  175. for( GuiMenuBar::MenuItem *item = mData->mMenuGui->firstMenuItem; item; item = item->nextMenuItem )
  176. ++count;
  177. return count;
  178. }
  179. //////////////////////////////////////////////////////////////////////////
  180. bool PopupMenu::canHandleID(U32 id)
  181. {
  182. return true;
  183. }
  184. bool PopupMenu::handleSelect(U32 command, const char *text /* = NULL */)
  185. {
  186. return dAtob(Con::executef(this, "onSelectItem", Con::getIntArg(command), text ? text : ""));
  187. }
  188. //////////////////////////////////////////////////////////////////////////
  189. void PopupMenu::showPopup(GuiCanvas *owner, S32 x /* = -1 */, S32 y /* = -1 */)
  190. {
  191. if(owner == NULL)
  192. return;
  193. GuiControl* editorGui;
  194. Sim::findObject("EditorGui", editorGui);
  195. if (editorGui)
  196. {
  197. GuiPopupMenuTextListCtrl* textList;
  198. GuiPopupMenuBackgroundCtrl* backgroundCtrl;
  199. Sim::findObject("PopUpMenuControl", backgroundCtrl);
  200. GuiControlProfile* profile;
  201. Sim::findObject("GuiMenubarProfile", profile);
  202. if (!profile)
  203. return;
  204. if (!backgroundCtrl)
  205. {
  206. textList = new GuiPopupMenuTextListCtrl();
  207. textList->registerObject();
  208. backgroundCtrl = new GuiPopupMenuBackgroundCtrl(textList);
  209. backgroundCtrl->registerObject("PopUpMenuControl");
  210. textList->setControlProfile(profile);
  211. backgroundCtrl->addObject(textList);
  212. }
  213. else
  214. {
  215. textList = dynamic_cast<GuiPopupMenuTextListCtrl*>(backgroundCtrl->first());
  216. }
  217. if (!backgroundCtrl || !textList)
  218. return;
  219. owner->pushDialogControl(backgroundCtrl, 10);
  220. backgroundCtrl->setExtent(editorGui->getExtent());
  221. textList->clear();
  222. textList->mMenu = mData->mMenuGui;
  223. textList->mMenuBar = findMenuBarCtrl();
  224. textList->mPopup = this;
  225. S32 textWidth = 0, width = 0;
  226. S32 acceleratorWidth = 0;
  227. GFont *font = profile->mFont;
  228. Point2I maxBitmapSize = Point2I(0, 0);
  229. S32 numBitmaps = profile->mBitmapArrayRects.size();
  230. if (numBitmaps)
  231. {
  232. RectI *bitmapBounds = profile->mBitmapArrayRects.address();
  233. for (S32 i = 0; i < numBitmaps; i++)
  234. {
  235. if (bitmapBounds[i].extent.x > maxBitmapSize.x)
  236. maxBitmapSize.x = bitmapBounds[i].extent.x;
  237. if (bitmapBounds[i].extent.y > maxBitmapSize.y)
  238. maxBitmapSize.y = bitmapBounds[i].extent.y;
  239. }
  240. }
  241. for (GuiMenuBar::MenuItem *walk = mData->mMenuGui->firstMenuItem; walk; walk = walk->nextMenuItem)
  242. {
  243. if (!walk->visible)
  244. continue;
  245. S32 iTextWidth = font->getStrWidth(walk->text);
  246. S32 iAcceleratorWidth = walk->accelerator ? font->getStrWidth(walk->accelerator) : 0;
  247. if (iTextWidth > textWidth)
  248. textWidth = iTextWidth;
  249. if (iAcceleratorWidth > acceleratorWidth)
  250. acceleratorWidth = iAcceleratorWidth;
  251. }
  252. width = textWidth + acceleratorWidth + maxBitmapSize.x * 2 + 2 + 4;
  253. textList->setCellSize(Point2I(width, font->getHeight() + 2));
  254. textList->clearColumnOffsets();
  255. textList->addColumnOffset(-1); // add an empty column in for the bitmap index.
  256. textList->addColumnOffset(maxBitmapSize.x + 1);
  257. textList->addColumnOffset(maxBitmapSize.x + 1 + textWidth + 4);
  258. U32 entryCount = 0;
  259. for (GuiMenuBar::MenuItem *walk = mData->mMenuGui->firstMenuItem; walk; walk = walk->nextMenuItem)
  260. {
  261. if (!walk->visible)
  262. continue;
  263. char buf[512];
  264. // If this menu item is a submenu, then set the isSubmenu to 2 to indicate
  265. // an arrow should be drawn. Otherwise set the isSubmenu normally.
  266. char isSubmenu = 1;
  267. if (walk->isSubmenu)
  268. isSubmenu = 2;
  269. char bitmapIndex = 1;
  270. if (walk->bitmapIndex >= 0 && (walk->bitmapIndex * 3 <= profile->mBitmapArrayRects.size()))
  271. bitmapIndex = walk->bitmapIndex + 2;
  272. dSprintf(buf, sizeof(buf), "%c%c\t%s\t%s", bitmapIndex, isSubmenu, walk->text, walk->accelerator ? walk->accelerator : "");
  273. textList->addEntry(entryCount, buf);
  274. if (!walk->enabled)
  275. textList->setEntryActive(entryCount, false);
  276. entryCount++;
  277. }
  278. Point2I pos = owner->getCursorPos();
  279. textList->setPosition(pos);
  280. //nudge in if we'd overshoot the screen
  281. S32 widthDiff = (textList->getPosition().x + textList->getExtent().x) - backgroundCtrl->getWidth();
  282. if (widthDiff > 0)
  283. {
  284. Point2I popupPos = textList->getPosition();
  285. textList->setPosition(popupPos.x - widthDiff, popupPos.y);
  286. }
  287. }
  288. }
  289. //////////////////////////////////////////////////////////////////////////
  290. void PopupMenu::attachToMenuBar(GuiCanvas *owner, S32 pos, const char *title)
  291. {
  292. if(owner == NULL || isAttachedToMenuBar())
  293. return;
  294. }
  295. // New version of above for use by MenuBar class. Do not use yet.
  296. void PopupMenu::attachToMenuBar(GuiCanvas *owner, S32 pos)
  297. {
  298. if(owner == NULL || isAttachedToMenuBar())
  299. return;
  300. //mData->mMenuBar = owner->setMenuBar();
  301. }
  302. void PopupMenu::removeFromMenuBar()
  303. {
  304. if(isAttachedToMenuBar())
  305. return;
  306. }
  307. S32 PopupMenu::getPosOnMenuBar()
  308. {
  309. return 0;
  310. }
  311. #endif