guiDropDownCtrl.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  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 "gui/buttons/guiDropDownCtrl.h"
  23. #include "gui/guiCanvas.h"
  24. #include "guiDropDownCtrl_ScriptBinding.h"
  25. #pragma region GuiDropDownBGCtrl
  26. GuiDropDownBGCtrl::GuiDropDownBGCtrl(GuiDropDownCtrl *ctrl)
  27. {
  28. mDropDownCtrl = ctrl;
  29. mBounds.point.set(0, 0);
  30. setField("profile", "GuiDefaultProfile");
  31. }
  32. void GuiDropDownBGCtrl::onTouchUp(const GuiEvent &event)
  33. {
  34. mDropDownCtrl->closeDropDown();
  35. }
  36. #pragma endregion
  37. #pragma region GuiDropDownListBoxCtrl
  38. GuiDropDownListBoxCtrl::GuiDropDownListBoxCtrl(GuiDropDownCtrl *ctrl)
  39. {
  40. mDropDownCtrl = ctrl;
  41. mBounds.point.set(0, 0);
  42. caller = ctrl;
  43. }
  44. void GuiDropDownListBoxCtrl::addSelection(LBItem *item, S32 index)
  45. {
  46. Parent::addSelection(item, index);
  47. mDropDownCtrl->itemSelected();
  48. }
  49. void GuiDropDownListBoxCtrl::setCurSel(S32 index)
  50. {
  51. Parent::setCurSel(index);
  52. }
  53. void GuiDropDownListBoxCtrl::onTouchUp(const GuiEvent &event)
  54. {
  55. Parent::onTouchUp(event);
  56. mDropDownCtrl->closeDropDown();
  57. }
  58. #pragma endregion
  59. IMPLEMENT_CONOBJECT(GuiDropDownCtrl);
  60. GuiDropDownCtrl::GuiDropDownCtrl()
  61. {
  62. mMaxHeight = 300;
  63. mBounds.extent.set(140, 24);
  64. mIsOpen = false;
  65. mActive = true;
  66. mText = StringTable->insert("none");
  67. setField("profile", "GuiDropDownProfile");
  68. mBackground = new GuiDropDownBGCtrl(this);
  69. AssertFatal(mBackground, "GuiDropDownCtrl: Failed to initialize GuiDropDownBGCtrl!");
  70. mBackgroundProfile = mBackground->mProfile;
  71. mBackgroundProfile->incRefCount();
  72. mListBox = new GuiDropDownListBoxCtrl(this);
  73. AssertFatal(mListBox, "GuiDropDownCtrl: Failed to initialize GuiDropDownListBoxCtrl!");
  74. mListBox->setField("profile", "GuiListBoxProfile");
  75. mListBoxProfile = mListBox->mProfile;
  76. mListBoxProfile->incRefCount();
  77. mListBox->setField("FitParentWidth", "1");
  78. mListBox->setField("AllowMultipleSelections", "0");
  79. mScroll = new GuiScrollCtrl();
  80. AssertFatal(mScroll, "GuiDropDownCtrl: Failed to initialize GuiScrollCtrl!");
  81. mScroll->setField("profile", "GuiScrollProfile");
  82. mScrollProfile = mScroll->mProfile;
  83. mScrollProfile->incRefCount();
  84. mScroll->setField("thumbProfile", "GuiScrollThumbProfile");
  85. mThumbProfile = mScroll->mThumbProfile;
  86. mThumbProfile->incRefCount();
  87. mScroll->setField("arrowProfile", "GuiScrollArrowProfile");
  88. mArrowProfile = mScroll->mArrowProfile;
  89. mArrowProfile->incRefCount();
  90. mScroll->setField("trackProfile", "GuiScrollTrackProfile");
  91. mTrackProfile = mScroll->mTrackProfile;
  92. mTrackProfile->incRefCount();
  93. mScroll->setField("hScrollBar", "AlwaysOff");
  94. mScroll->setField("vScrollBar", "Dynamic");
  95. mScroll->setField("constantThumbHeight", "0");
  96. mUseConstantHeightThumb = false;
  97. mScroll->setField("scrollBarThickness", "12");
  98. mScrollBarThickness = 12;
  99. mScroll->setField("showArrowButtons", "0");
  100. mShowArrowButtons = false;
  101. mScroll->addObject(mListBox);
  102. mBackground->addObject(mScroll);
  103. }
  104. void GuiDropDownCtrl::initPersistFields()
  105. {
  106. Parent::initPersistFields();
  107. addField("maxHeight", TypeBool, Offset(mMaxHeight, GuiDropDownCtrl));
  108. addField("scrollProfile", TypeGuiProfile, Offset(mScrollProfile, GuiDropDownCtrl));
  109. addField("thumbProfile", TypeGuiProfile, Offset(mThumbProfile, GuiDropDownCtrl));
  110. addField("arrowProfile", TypeGuiProfile, Offset(mArrowProfile, GuiDropDownCtrl));
  111. addField("trackProfile", TypeGuiProfile, Offset(mTrackProfile, GuiDropDownCtrl));
  112. addField("listBoxProfile", TypeGuiProfile, Offset(mListBoxProfile, GuiDropDownCtrl));
  113. addField("backgroundProfile", TypeGuiProfile, Offset(mBackgroundProfile, GuiDropDownCtrl));
  114. addField("constantThumbHeight", TypeBool, Offset(mUseConstantHeightThumb, GuiDropDownCtrl));
  115. addField("showArrowButtons", TypeBool, Offset(mShowArrowButtons, GuiDropDownCtrl));
  116. addField("scrollBarThickness", TypeS32, Offset(mScrollBarThickness, GuiDropDownCtrl));
  117. }
  118. void GuiDropDownCtrl::onTouchUp(const GuiEvent &event)
  119. {
  120. if (!mActive)
  121. return;
  122. Parent::onTouchUp(event);
  123. mouseUnlock();
  124. if (!mIsOpen)
  125. {
  126. openDropDown();
  127. }
  128. else
  129. {
  130. closeDropDown();
  131. }
  132. }
  133. GuiControlState GuiDropDownCtrl::getCurrentState()
  134. {
  135. if (!mActive)
  136. return GuiControlState::DisabledState;
  137. else if (mDepressed || mIsOpen)
  138. return GuiControlState::SelectedState;
  139. else if (mMouseOver)
  140. return GuiControlState::HighlightState;
  141. else
  142. return GuiControlState::NormalState;
  143. }
  144. void GuiDropDownCtrl::onRender(Point2I offset, const RectI& updateRect)
  145. {
  146. GuiControlState currentState = getCurrentState();
  147. RectI ctrlRect = applyMargins(offset, mBounds.extent, currentState, mProfile);
  148. renderUniversalRect(ctrlRect, mProfile, currentState, getFillColor(currentState), true);
  149. //Get the content area
  150. dglSetBitmapModulation(getFontColor(mProfile, currentState));
  151. RectI fillRect = applyBorders(ctrlRect.point, ctrlRect.extent, currentState, mProfile);
  152. RectI contentRect = applyPadding(fillRect.point, fillRect.extent, currentState, mProfile);
  153. //Render the triangle
  154. RectI drawArea = RectI(contentRect.point.x + contentRect.extent.x - contentRect.extent.y, contentRect.point.y, contentRect.extent.y, contentRect.extent.y);
  155. ColorI color = ColorI(getFontColor(mProfile, currentState));
  156. renderTriangleIcon(drawArea, color, GuiDirection::Down, 8);
  157. contentRect.extent.x -= contentRect.extent.y;
  158. //Render the text
  159. S32 index = mListBox->getSelectedItem();
  160. if (index == -1)
  161. {
  162. renderText(contentRect.point, contentRect.extent, mText, mProfile);
  163. }
  164. else
  165. {
  166. if (mListBox->getItemHasColor(index))
  167. {
  168. //Draw the bullet
  169. RectI drawArea = RectI(contentRect.point.x, contentRect.point.y, contentRect.extent.y, contentRect.extent.y);
  170. ColorI color = ColorI(mListBox->getItemColor(index));
  171. renderColorBullet(drawArea, color, 5);
  172. contentRect.point.x += contentRect.extent.y;
  173. contentRect.extent.x -= contentRect.extent.y;
  174. }
  175. renderText(contentRect.point, contentRect.extent, mListBox->getItemText(index), mProfile);
  176. }
  177. }
  178. bool GuiDropDownCtrl::onKeyDown(const GuiEvent &event)
  179. {
  180. //if the control is a dead end, don't process the input:
  181. if (!mVisible || !mActive || !mAwake)
  182. return false;
  183. //see if the key down is a <return> or not
  184. if (event.keyCode == KEY_RETURN && event.modifier == 0)
  185. {
  186. if(!mIsOpen)
  187. {
  188. openDropDown();
  189. }
  190. else
  191. {
  192. closeDropDown();
  193. }
  194. return true;
  195. }
  196. else if (mIsOpen)
  197. {
  198. return mListBox->onKeyDown(event);
  199. }
  200. return false;
  201. }
  202. void GuiDropDownCtrl::onAction() //called when the button is clicked.
  203. {
  204. if (!mActive)
  205. return;
  206. setUpdate();
  207. }
  208. void GuiDropDownCtrl::itemSelected()
  209. {
  210. if (mConsoleCommand[0])
  211. Con::evaluate(mConsoleCommand, false);
  212. }
  213. void GuiDropDownCtrl::openDropDown()
  214. {
  215. if (mIsOpen)
  216. return;
  217. GuiCanvas *root = getRoot();
  218. AssertFatal(root, "GuiDropDownCtrl::openDropDown: Unable to optain the Canvas!");
  219. mBackground->mBounds.extent = root->mBounds.extent;
  220. //Update all pass through values
  221. mBackground->setControlProfile(mBackgroundProfile);
  222. mListBox->setControlProfile(mListBoxProfile);
  223. mScroll->setControlProfile(mScrollProfile);
  224. mScroll->setControlThumbProfile(mThumbProfile);
  225. mScroll->setControlArrowProfile(mArrowProfile);
  226. mScroll->setControlTrackProfile(mTrackProfile);
  227. mScroll->mUseConstantHeightThumb = mUseConstantHeightThumb;
  228. mScroll->mScrollBarThickness = mScrollBarThickness;
  229. mScroll->mShowArrowButtons = mShowArrowButtons;
  230. //Set the size of the scroll control.
  231. mListBox->updateSize();
  232. S32 width = mClamp(mListBox->mBounds.extent.x, mBounds.extent.x, mBounds.extent.x * 2);
  233. S32 height = mClamp(mListBox->mBounds.extent.y, 10, mMaxHeight);
  234. Point2I pos = localToGlobalCoord(Point2I(0,0));
  235. //Is there enough space below?
  236. if ((height + pos.y + mBounds.extent.y) <= root->mBounds.extent.y)
  237. {
  238. pos.y += mBounds.extent.y;
  239. }
  240. else if (height <= pos.y) //Is there enough space above?
  241. {
  242. pos.y -= height;
  243. }
  244. else if (pos.y < (root->mBounds.extent.y - (pos.y + mBounds.extent.y))) //Is there more space below?
  245. {
  246. pos.y += mBounds.extent.y;
  247. height = root->mBounds.extent.y - pos.y;
  248. }
  249. else //There must be more space above
  250. {
  251. height = pos.y;
  252. pos.y = 0;
  253. }
  254. mScroll->resize(pos, Point2I(width, height));
  255. root->pushDialogControl(mBackground, 99);
  256. mListBox->ScrollToIndex(mListBox->getSelectedItem());
  257. mIsOpen = true;
  258. setFirstResponder();
  259. if (isMethod("onOpen"))
  260. Con::executef(this, 1, "onOpen");
  261. }
  262. void GuiDropDownCtrl::closeDropDown()
  263. {
  264. if(!mIsOpen)
  265. return;
  266. GuiCanvas *root = mBackground->getRoot();
  267. if (!root)
  268. {
  269. return;
  270. }
  271. root->popDialogControl(mBackground);
  272. mIsOpen = false;
  273. if (isMethod("onClose"))
  274. Con::executef(this, 1, "onClose");
  275. }
  276. bool GuiDropDownCtrl::onWake()
  277. {
  278. if (!Parent::onWake())
  279. return false;
  280. if (mBackgroundProfile != NULL)
  281. mBackgroundProfile->incRefCount();
  282. if (mListBoxProfile != NULL)
  283. mListBoxProfile->incRefCount();
  284. if (mScrollProfile != NULL)
  285. mScrollProfile->incRefCount();
  286. if (mThumbProfile != NULL)
  287. mThumbProfile->incRefCount();
  288. if (mTrackProfile != NULL)
  289. mTrackProfile->incRefCount();
  290. if (mArrowProfile != NULL)
  291. mArrowProfile->incRefCount();
  292. return true;
  293. }
  294. void GuiDropDownCtrl::onSleep()
  295. {
  296. Parent::onSleep();
  297. if (mBackgroundProfile != NULL)
  298. mBackgroundProfile->decRefCount();
  299. if (mListBoxProfile != NULL)
  300. mListBoxProfile->decRefCount();
  301. if (mScrollProfile != NULL)
  302. mScrollProfile->decRefCount();
  303. if (mThumbProfile != NULL)
  304. mThumbProfile->decRefCount();
  305. if (mTrackProfile != NULL)
  306. mTrackProfile->decRefCount();
  307. if (mArrowProfile != NULL)
  308. mArrowProfile->decRefCount();
  309. }
  310. void GuiDropDownCtrl::setControlBackgroundProfile(GuiControlProfile* prof)
  311. {
  312. AssertFatal(prof, "GuiDropDownCtrl::setControlBackgroundProfile: invalid background profile");
  313. if (prof == mBackgroundProfile)
  314. return;
  315. if (mAwake)
  316. mBackgroundProfile->decRefCount();
  317. mBackgroundProfile = prof;
  318. if (mAwake)
  319. mBackgroundProfile->incRefCount();
  320. }
  321. void GuiDropDownCtrl::setControlListBoxProfile(GuiControlProfile* prof)
  322. {
  323. AssertFatal(prof, "GuiDropDownCtrl::setControlListBoxProfile: invalid list box profile");
  324. if (prof == mListBoxProfile)
  325. return;
  326. if (mAwake)
  327. mListBoxProfile->decRefCount();
  328. mListBoxProfile = prof;
  329. if (mAwake)
  330. mListBoxProfile->incRefCount();
  331. }
  332. void GuiDropDownCtrl::setControlScrollProfile(GuiControlProfile* prof)
  333. {
  334. AssertFatal(prof, "GuiDropDownCtrl::setControlScrollProfile: invalid scroll profile");
  335. if (prof == mScrollProfile)
  336. return;
  337. if (mAwake)
  338. mScrollProfile->decRefCount();
  339. mScrollProfile = prof;
  340. if (mAwake)
  341. mScrollProfile->incRefCount();
  342. }
  343. void GuiDropDownCtrl::setControlThumbProfile(GuiControlProfile* prof)
  344. {
  345. AssertFatal(prof, "GuiDropDownCtrl::setControlThumbProfile: invalid thumb profile");
  346. if (prof == mThumbProfile)
  347. return;
  348. if (mAwake)
  349. mThumbProfile->decRefCount();
  350. mThumbProfile = prof;
  351. if (mAwake)
  352. mThumbProfile->incRefCount();
  353. }
  354. void GuiDropDownCtrl::setControlTrackProfile(GuiControlProfile* prof)
  355. {
  356. AssertFatal(prof, "GuiDropDownCtrl::setControlTrackProfile: invalid track profile");
  357. if (prof == mTrackProfile)
  358. return;
  359. if (mAwake)
  360. mTrackProfile->decRefCount();
  361. mTrackProfile = prof;
  362. if (mAwake)
  363. mTrackProfile->incRefCount();
  364. }
  365. void GuiDropDownCtrl::setControlArrowProfile(GuiControlProfile* prof)
  366. {
  367. AssertFatal(prof, "GuiDropDownCtrl::setControlArrowProfile: invalid arrow profile");
  368. if (prof == mArrowProfile)
  369. return;
  370. if (mAwake)
  371. mArrowProfile->decRefCount();
  372. mArrowProfile = prof;
  373. if (mAwake)
  374. mArrowProfile->incRefCount();
  375. }