guiDropDownCtrl.cc 12 KB

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