BsGUIDropDownBox.h 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. #pragma once
  2. #include "BsPrerequisites.h"
  3. #include "BsGUIWidget.h"
  4. #include "CmVector2I.h"
  5. #include <boost/signal.hpp>
  6. namespace BansheeEngine
  7. {
  8. struct BS_EXPORT GUIDropDownData
  9. {
  10. CM::Vector<GUIDropDownDataEntry>::type entries;
  11. CM::UnorderedMap<CM::WString, CM::HString>::type localizedNames;
  12. };
  13. class BS_EXPORT GUIDropDownDataEntry
  14. {
  15. enum class Type
  16. {
  17. Separator,
  18. Entry,
  19. SubMenu
  20. };
  21. public:
  22. static GUIDropDownDataEntry separator();
  23. static GUIDropDownDataEntry button(const CM::WString& label, std::function<void()> callback);
  24. static GUIDropDownDataEntry subMenu(const CM::WString& label, const GUIDropDownData& data);
  25. bool isSeparator() const { return mType == Type::Separator; }
  26. bool isSubMenu() const { return mType == Type::SubMenu; }
  27. const CM::WString& getLabel() const { return mLabel; }
  28. std::function<void()> getCallback() const { return mCallback; }
  29. const GUIDropDownData& getSubMenuData() const { return mChildData; }
  30. private:
  31. GUIDropDownDataEntry() { }
  32. std::function<void()> mCallback;
  33. GUIDropDownData mChildData;
  34. CM::WString mLabel;
  35. Type mType;
  36. };
  37. /**
  38. * @brief Determines how will the drop down box be placed. Usually the system will attempt to position
  39. * the drop box in a way so all elements can fit, and this class allows you to specify some limitations
  40. * on how that works.
  41. *
  42. * @note For example, list boxes usually want drop down boxes to be placed above or below them, while
  43. * context menus may want to have them placed around a single point in any direction.
  44. */
  45. class BS_EXPORT GUIDropDownAreaPlacement
  46. {
  47. public:
  48. enum class Type
  49. {
  50. Position,
  51. BoundsVert,
  52. BoundsHorz
  53. };
  54. /**
  55. * @brief Drop down box will be placed at the specified position. By default the system
  56. * prefers the top left corner of the box to correspond to the position, but if
  57. * other corners offer more space for the contents, those will be used instead.
  58. */
  59. static GUIDropDownAreaPlacement aroundPosition(const CM::Vector2I& position);
  60. /**
  61. * @brief Drop down box will be placed at the specified bounds. Box will be horizontally aligned to the left
  62. * of the provided bounds. Vertically system prefers placing the box at the bottom of the bounds, but may choose
  63. * to align it with the top of the bounds if it offers more space for the contents.
  64. */
  65. static GUIDropDownAreaPlacement aroundBoundsVert(const CM::RectI& bounds);
  66. /**
  67. * @brief Drop down box will be placed at the specified bounds. Box will be vertically aligned to the top
  68. * of the provided bounds. Horizontally system prefers placing the box at the right of the bounds, but may choose
  69. * to align it with the left of the bounds if it offers more space for the contents.
  70. */
  71. static GUIDropDownAreaPlacement aroundBoundsHorz(const CM::RectI& bounds);
  72. Type getType() const { return mType; }
  73. const CM::RectI& getBounds() const { return mBounds; }
  74. const CM::Vector2I& getPosition() const { return mPosition; }
  75. private:
  76. GUIDropDownAreaPlacement() { }
  77. Type mType;
  78. CM::RectI mBounds;
  79. CM::Vector2I mPosition;
  80. };
  81. enum class GUIDropDownType
  82. {
  83. ListBox,
  84. ContextMenu,
  85. MenuBar
  86. };
  87. /**
  88. * @brief This is a generic GUI drop down box class that can be used for:
  89. * list boxes, menu bars or context menus.
  90. */
  91. class BS_EXPORT GUIDropDownBox : public GUIWidget
  92. {
  93. public:
  94. GUIDropDownBox(const CM::HSceneObject& parent, CM::Viewport* target, const GUIDropDownAreaPlacement& placement,
  95. const GUIDropDownData& dropDownData, const GUISkin& skin, GUIDropDownType type);
  96. ~GUIDropDownBox();
  97. private:
  98. struct DropDownSubMenu
  99. {
  100. GUIDropDownBox* mOwner;
  101. GUIDropDownType mType;
  102. GUIDropDownData mData;
  103. CM::UINT32 mPage;
  104. CM::INT32 x, y;
  105. CM::UINT32 width, height;
  106. CM::RectI mVisibleBounds;
  107. CM::RectI mAvailableBounds;
  108. CM::UINT32 mDepthOffset;
  109. bool mOpenedUpward;
  110. CM::Vector<GUITexture*>::type mCachedSeparators;
  111. CM::Vector<GUIButton*>::type mCachedEntryBtns;
  112. CM::Vector<GUIButton*>::type mCachedExpEntryBtns;
  113. GUIButton* mScrollUpBtn;
  114. GUIButton* mScrollDownBtn;
  115. GUITexture* mBackgroundFrame;
  116. GUIArea* mBackgroundArea;
  117. GUIArea* mContentArea;
  118. GUILayout* mContentLayout;
  119. DropDownSubMenu* mSubMenu;
  120. DropDownSubMenu(GUIDropDownBox* owner, const GUIDropDownAreaPlacement& placement,
  121. const CM::RectI& availableBounds, const GUIDropDownData& dropDownData, GUIDropDownType type, CM::UINT32 depthOffset);
  122. ~DropDownSubMenu();
  123. void updateGUIElements();
  124. void scrollDown();
  125. void scrollUp();
  126. CM::UINT32 getElementHeight(CM::UINT32 idx) const;
  127. void elementClicked(CM::UINT32 idx);
  128. void openSubMenu(GUIButton* source, CM::UINT32 elementIdx);
  129. void closeSubMenu();
  130. CM::RectI getVisibleBounds() const { return mVisibleBounds; }
  131. CM::HString getElementLocalizedName(CM::UINT32 idx) const;
  132. };
  133. static const CM::UINT32 DROP_DOWN_BOX_WIDTH;
  134. CM::String mScrollUpStyle;
  135. CM::String mScrollDownStyle;
  136. CM::String mEntryBtnStyle;
  137. CM::String mEntryExpBtnStyle;
  138. CM::String mSeparatorStyle;
  139. CM::String mBackgroundStyle;
  140. HSpriteTexture mScrollUpBtnArrow;
  141. HSpriteTexture mScrollDownBtnArrow;
  142. DropDownSubMenu* mRootMenu;
  143. GUIDropDownHitBox* mHitBox;
  144. // Captures mouse clicks so that we don't trigger elements outside the drop down box when we just want to close it.
  145. // (Particular example is clicking on the button that opened the drop down box in the first place. Clicking will cause
  146. // the drop down to lose focus and close, but if the button still processes the mouse click it will be immediately opened again)
  147. GUIDropDownHitBox* mCaptureHitBox;
  148. CM::UnorderedMap<CM::WString, CM::HString>::type mLocalizedEntryNames;
  149. void notifySubMenuOpened(DropDownSubMenu* subMenu);
  150. void notifySubMenuClosed(DropDownSubMenu* subMenu);
  151. void dropDownFocusLost();
  152. };
  153. }