BsGUIDropDownMenu.h 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. #pragma once
  2. #include "BsPrerequisites.h"
  3. #include "BsGUIWidget.h"
  4. #include "BsVector2I.h"
  5. #include "BsRect2I.h"
  6. #include "BsEvent.h"
  7. #include "BsDropDownAreaPlacement.h"
  8. namespace BansheeEngine
  9. {
  10. /**
  11. * @brief Contains items used for initializing one level in a drop down box hierarchy.
  12. */
  13. struct BS_EXPORT GUIDropDownData
  14. {
  15. Vector<GUIDropDownDataEntry> entries;
  16. UnorderedMap<WString, HString> localizedNames;
  17. };
  18. /**
  19. * @brief A set of parameters used for initializing a drop down box.
  20. */
  21. struct DROP_DOWN_BOX_DESC
  22. {
  23. Viewport* target; /**< Viewport on which to open the drop down box. */
  24. DropDownAreaPlacement placement; /**< Determines how is the drop down box positioned in the visible area. */
  25. GUIDropDownData dropDownData; /**< Data to use for initializing menu items of the drop down box. */
  26. HGUISkin skin; /**< Skin to use for drop down box GUI elements. */
  27. Vector<Rect2I> additionalBounds; /**< Additional bounds that control what is considered the inside or the outside of the drop down box. */
  28. };
  29. /**
  30. * @brief Represents a single entry in a drop down box.
  31. */
  32. class BS_EXPORT GUIDropDownDataEntry
  33. {
  34. enum class Type
  35. {
  36. Separator,
  37. Entry,
  38. SubMenu
  39. };
  40. public:
  41. /**
  42. * @brief Creates a new separator entry.
  43. */
  44. static GUIDropDownDataEntry separator();
  45. /**
  46. * @brief Creates a new button entry with the specified callback that is triggered
  47. * when button is selected.
  48. */
  49. static GUIDropDownDataEntry button(const WString& label, std::function<void()> callback, const WString& shortcutTag = StringUtil::WBLANK);
  50. /**
  51. * @brief Creates a new sub-menu entry that will open the provided drop down data
  52. * sub-menu when activated.
  53. */
  54. static GUIDropDownDataEntry subMenu(const WString& label, const GUIDropDownData& data);
  55. /**
  56. * @brief Check is the entry a separator.
  57. */
  58. bool isSeparator() const { return mType == Type::Separator; }
  59. /**
  60. * @brief Check is the entry a sub menu.
  61. */
  62. bool isSubMenu() const { return mType == Type::SubMenu; }
  63. /**
  64. * @brief Returns display label of the entry (if an entry is a button or a sub-menu).
  65. */
  66. const WString& getLabel() const { return mLabel; }
  67. /**
  68. * @brief Returns the shortcut key combination string that is to be displayed along the entry label.
  69. */
  70. const WString& getShortcutTag() const { return mShortcutTag; }
  71. /**
  72. * @brief Returns a button callback if the entry (if an entry is a button).
  73. */
  74. std::function<void()> getCallback() const { return mCallback; }
  75. /**
  76. * @brief Returns sub-menu data that is used for creating a sub-menu (if an entry is a sub-menu).
  77. */
  78. const GUIDropDownData& getSubMenuData() const { return mChildData; }
  79. private:
  80. GUIDropDownDataEntry() { }
  81. std::function<void()> mCallback;
  82. GUIDropDownData mChildData;
  83. WString mLabel;
  84. WString mShortcutTag;
  85. Type mType;
  86. };
  87. /**
  88. * @brief Type of drop down box types.
  89. */
  90. enum class GUIDropDownType
  91. {
  92. ListBox,
  93. ContextMenu,
  94. MenuBar
  95. };
  96. /**
  97. * @brief This is a generic GUI drop down box class that can be used for:
  98. * list boxes, menu bars or context menus.
  99. */
  100. class BS_EXPORT GUIDropDownMenu : public GUIWidget
  101. {
  102. public:
  103. /**
  104. * @brief Creates a new drop down box widget.
  105. *
  106. * @param parent Parent scene object to attach the drop down box to.
  107. * @param desc Various parameters that control the drop down menu features and content.
  108. * @param type Specific type of drop down box to display.
  109. */
  110. GUIDropDownMenu(const HSceneObject& parent, const DROP_DOWN_BOX_DESC& desc, GUIDropDownType type);
  111. ~GUIDropDownMenu();
  112. private:
  113. /**
  114. * @brief Contains data about a single drop down box sub-menu
  115. */
  116. struct DropDownSubMenu
  117. {
  118. /**
  119. * @brief Represents a single sub-menu page.
  120. */
  121. struct PageInfo
  122. {
  123. UINT32 idx;
  124. UINT32 start;
  125. UINT32 end;
  126. UINT32 height;
  127. };
  128. public:
  129. /**
  130. * @brief Creates a new drop down box sub-menu
  131. *
  132. * @param owner Owner drop down box this sub menu belongs to.
  133. * @param parent Parent sub-menu. Can be null.
  134. * @param placement Determines how is the sub-menu positioned in the visible area.
  135. * @param availableBounds Available bounds (in pixels) in which the sub-menu may be opened.
  136. * @param dropDownData Data to use for initializing menu items of the sub-menu.
  137. * @param skin Skin to use for sub-menu GUI elements.
  138. * @param depthOffset How much to offset the sub-menu depth. We want deeper levels of the
  139. * sub-menu hierarchy to be in front of lower levels, so you should
  140. * increase this value for each level of the sub-menu hierarchy.
  141. */
  142. DropDownSubMenu(GUIDropDownMenu* owner, DropDownSubMenu* parent, const DropDownAreaPlacement& placement,
  143. const Rect2I& availableBounds, const GUIDropDownData& dropDownData, GUIDropDownType type, UINT32 depthOffset);
  144. ~DropDownSubMenu();
  145. /**
  146. * @brief Recreates all internal GUI elements for the entries of the current sub-menu page.
  147. */
  148. void updateGUIElements();
  149. /**
  150. * @brief Moves the sub-menu to the previous page and displays its elements, if available.
  151. */
  152. void scrollDown();
  153. /**
  154. * @brief Moves the sub-menu to the next page and displays its elements, if available.
  155. */
  156. void scrollUp();
  157. /**
  158. * @brief Moves the sub-menu to the first page and displays its elements.
  159. */
  160. void scrollToTop();
  161. /**
  162. * @brief Moves the sub-menu to the last page and displays its elements.
  163. */
  164. void scrollToBottom();
  165. /**
  166. * @brief Calculates ranges for all the pages of the sub-menu.
  167. */
  168. Vector<PageInfo> getPageInfos() const;
  169. /**
  170. * @brief Called when the user activates an element with the specified index.
  171. *
  172. * @param bounds Bounds of the GUI element that is used as a visual representation
  173. * of this drop down element.
  174. */
  175. void elementActivated(UINT32 idx, const Rect2I& bounds);
  176. /**
  177. * @brief Called when the user selects an element with the specified index.
  178. *
  179. * @param idx Index of the element that was selected.
  180. */
  181. void elementSelected(UINT32 idx);
  182. /**
  183. * @brief Called when the user wants to close the currently open sub-menu.
  184. */
  185. void closeSubMenu();
  186. /**
  187. * @brief Closes this sub-menu.
  188. */
  189. void close();
  190. /**
  191. * @brief Returns actual visible bounds of the sub-menu.
  192. */
  193. Rect2I getVisibleBounds() const { return mVisibleBounds; }
  194. /**
  195. * @brief Returns the drop box object that owns this sub-menu.
  196. */
  197. GUIDropDownMenu* getOwner() const { return mOwner; }
  198. public:
  199. GUIDropDownMenu* mOwner;
  200. GUIDropDownType mType;
  201. GUIDropDownData mData;
  202. UINT32 mPage;
  203. INT32 x, y;
  204. UINT32 width, height;
  205. Rect2I mVisibleBounds;
  206. Rect2I mAvailableBounds;
  207. UINT32 mDepthOffset;
  208. bool mOpenedUpward;
  209. GUIButton* mScrollUpBtn;
  210. GUIButton* mScrollDownBtn;
  211. GUIDropDownContent* mContent;
  212. GUITexture* mBackgroundFrame;
  213. GUIPanel* mBackgroundPanel;
  214. GUIPanel* mContentPanel;
  215. GUILayout* mContentLayout;
  216. DropDownSubMenu* mParent;
  217. DropDownSubMenu* mSubMenu;
  218. };
  219. private:
  220. friend class GUIDropDownContent;
  221. /**
  222. * @brief Called when the specified sub-menu is opened.
  223. */
  224. void notifySubMenuOpened(DropDownSubMenu* subMenu);
  225. /**
  226. * @brief Called when the specified sub-menu is opened.
  227. */
  228. void notifySubMenuClosed(DropDownSubMenu* subMenu);
  229. /**
  230. * @brief Called when the drop down box loses focus (and should be closed).
  231. */
  232. void dropDownFocusLost();
  233. /**
  234. * @copydoc GUIWidget::onDestroyed
  235. */
  236. void onDestroyed() override;
  237. private:
  238. static const UINT32 DROP_DOWN_BOX_WIDTH;
  239. String mScrollUpStyle;
  240. String mScrollDownStyle;
  241. String mBackgroundStyle;
  242. String mContentStyle;
  243. HSpriteTexture mScrollUpBtnArrow;
  244. HSpriteTexture mScrollDownBtnArrow;
  245. DropDownSubMenu* mRootMenu;
  246. GUIDropDownHitBox* mFrontHitBox;
  247. GUIDropDownHitBox* mBackHitBox;
  248. // Captures mouse clicks so that we don't trigger elements outside the drop down box when we just want to close it.
  249. // (Particular example is clicking on the button that opened the drop down box in the first place. Clicking will cause
  250. // the drop down to lose focus and close, but if the button still processes the mouse click it will be immediately opened again)
  251. GUIDropDownHitBox* mCaptureHitBox;
  252. Vector<Rect2I> mAdditionalCaptureBounds;
  253. };
  254. }