BsDockManager.h 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. #pragma once
  2. #include "BsEditorPrerequisites.h"
  3. #include "BsGUIElementContainer.h"
  4. #include "BsRect2I.h"
  5. namespace BansheeEngine
  6. {
  7. /**
  8. * @brief GUI element that allows editor widgets to be docked in it using arbitrary
  9. * layouts. Docked widgets can be resized, undocked, maximizes or closed as needed.
  10. */
  11. class DockManager : public GUIElementContainer
  12. {
  13. public:
  14. /**
  15. * @brief Contains information about a single dock area. Each container can be a parent to
  16. * two other containers or may contain a widget, which results in a container hierarchy.
  17. * Two children can be split vertically or horizontally at an user-defined point.
  18. */
  19. class DockContainer
  20. {
  21. public:
  22. DockContainer(DockManager* manager);
  23. DockContainer(DockManager* manager, DockContainer* parent);
  24. ~DockContainer();
  25. /**
  26. * @brief Determines the position and size of the container, relative to the parent dock manager.
  27. */
  28. void setArea(INT32 x, INT32 y, UINT32 width, UINT32 height);
  29. /**
  30. * @brief Transforms the container from non-leaf (parent to other containers)
  31. * to leaf (parent to widgets). This involves creating a widget container to
  32. * which you can dock widgets to.
  33. *
  34. * @param parentWindow Editor window of the parent dock manager.
  35. */
  36. void makeLeaf(EditorWindowBase* parentWindow);
  37. /**
  38. * @brief Transforms the container from non-leaf (parent to other containers)
  39. * to leaf (parent to widgets). Unlike the other overload this one accepts
  40. * a previously created widget container.
  41. *
  42. * @param guiWidgetSO Parent SceneObject of the GUIWidget used by the provided widget container.
  43. * @param existingContainer An existing widget container that may be used for docking widgets.
  44. */
  45. void makeLeaf(const HSceneObject& guiWidgetSO, EditorWidgetContainer* existingContainer);
  46. /**
  47. * @brief Splits a leaf container containing a widget container (or may be empty in the case of root with no elements)
  48. * into a container parent to two other containers.
  49. *
  50. * @param horizontal Whether the split is horizontal (true) or vertical (false.
  51. * @param newChildIsFirst Determines to which child should the widget container from this object be moved to.
  52. * If the new child is first, then bottom or right (for horizontal and vertical respectively)
  53. * will receive the current widget container, and opposite if it's not first.
  54. * @param splitPosition Determines at what position(in percent) should this container be split. User can modify this later
  55. * via a dock slider.
  56. */
  57. void splitContainer(bool horizontal, bool newChildIsFirst, float splitPosition = 0.5f);
  58. /**
  59. * @brief Splits a leaf container containing a widget container (or may be empty in the case of root with no elements)
  60. * into a container parent to two other containers. Unlike "splitContainer" new containers aren't created automatically
  61. * but you must provide existing ones. If this container is non-leaf its widget container will be destroyed.
  62. *
  63. * @param first Container to insert into the first child slot (left if vertical split, top if horizontal split).
  64. * @param second Container to insert into the second child slot (right if vertical split, bottom if horizontal split).
  65. * @param horizontal Whether the split is horizontal (true) or vertical (false.
  66. * @param splitPosition Determines at what position(in percent) should this container be split. User can modify this later
  67. * via a dock slider.
  68. */
  69. void makeSplit(DockContainer* first, DockContainer* second, bool horizontal, float splitPosition);
  70. /**
  71. * @brief Adds a new widget to the left side of the container. If the container is leaf it will
  72. * be split into two containers vertically.
  73. */
  74. void addLeft(EditorWidgetBase* widget);
  75. /**
  76. * @brief Adds a new widget to the right side of the container. If the container is leaf it will
  77. * be split into two containers vertically.
  78. */
  79. void addRight(EditorWidgetBase* widget);
  80. /**
  81. * @brief Adds a new widget to the top side of the container. If the container is leaf it will
  82. * be split into two containers horizontally.
  83. */
  84. void addTop(EditorWidgetBase* widget);
  85. /**
  86. * @brief Adds a new widget to the bottom side of the container. If the container is leaf it will
  87. * be split into two containers horizontally.
  88. */
  89. void addBottom(EditorWidgetBase* widget);
  90. /**
  91. * @brief Adds an existing widget to this leaf container.
  92. */
  93. void addWidget(EditorWidgetBase* widget);
  94. /**
  95. * @brief Attempts to find a widget with the specified name, opens it
  96. * and adds it to this leaf container.
  97. */
  98. void addWidget(const String& name);
  99. /**
  100. * @brief Update to be called once per frame. Calls updates on all child widgets.
  101. */
  102. void update();
  103. /**
  104. * @brief Attempts to find an existing leaf dock container with the specified
  105. * widget container. Returns null if one cannot be found.
  106. */
  107. DockContainer* find(EditorWidgetContainer* widgetContainer);
  108. /**
  109. * @brief Searches for a container at the specified position. Call this at this top-most
  110. * container in order to search them all.
  111. *
  112. * @param pos Position is relative to the container area.
  113. *
  114. * @return null if it fails, else the found DockContainer at position.
  115. */
  116. DockContainer* findAtPos(const Vector2I& pos);
  117. /**
  118. * @brief Returns the bounds of the container that are to be considered
  119. * dockable and interactable.
  120. */
  121. Rect2I getContentBounds() const;
  122. bool mIsLeaf;
  123. DockContainer* mChildren[2];
  124. DockContainer* mParent;
  125. DockManager* mManager;
  126. EditorWidgetContainer* mWidgets;
  127. HSceneObject mGUIWidgetSO;
  128. GUIDockSlider* mSlider;
  129. Rect2I mArea;
  130. float mSplitPosition;
  131. bool mIsHorizontal;
  132. static const UINT32 SLIDER_SIZE;
  133. static const UINT32 MIN_CHILD_SIZE;
  134. private:
  135. /**
  136. * @brief Updates sizes and positions of all child containers.
  137. * Normally called when parent area changes.
  138. */
  139. void updateChildAreas();
  140. /**
  141. * @brief Triggered whenever the user drags the GUI slider belonging to this container.
  142. */
  143. void sliderDragged(const Vector2I& delta);
  144. /**
  145. * @brief Triggered whenever the user closes or undocks a widget belonging to this container.
  146. */
  147. void widgetRemoved();
  148. };
  149. /**
  150. * @brief Available dock locations for the dock manager.
  151. */
  152. enum class DockLocation
  153. {
  154. Top,
  155. Bottom,
  156. Left,
  157. Right,
  158. None
  159. };
  160. public:
  161. /**
  162. * @brief Creates a new dock manager for the specified window.
  163. */
  164. static DockManager* create(EditorWindowBase* parentWindow);
  165. /**
  166. * @brief Internal method. Called once every frame.
  167. */
  168. void update();
  169. /**
  170. * @brief Inserts a new widget at the specified location.
  171. *
  172. * @param relativeTo Container relative to which to insert the widget. Can be null in which case
  173. * the widget is inserted at the root.
  174. * @param widgetToInsert Widget we want to insert into the dock layout.
  175. * @param location Location to insert the widget at, relative to "relativeTo" container.
  176. * If "relativeTo" is null this is ignored.
  177. */
  178. void insert(EditorWidgetContainer* relativeTo, EditorWidgetBase* widgetToInsert, DockLocation location);
  179. /**
  180. * @brief Returns a saved layout of all the currently docked widgets and their positions
  181. * and areas.
  182. */
  183. DockManagerLayoutPtr getLayout() const;
  184. /**
  185. * @brief Sets a previously saved layout of docked widgets. This will close all currently active
  186. * widgets and open and position new ones according to the layout.
  187. */
  188. void setLayout(const DockManagerLayoutPtr& layout);
  189. /**
  190. * @brief Changes the position and size of the dock manager.
  191. */
  192. void setArea(INT32 x, INT32 y, UINT32 width, UINT32 height);
  193. /**
  194. * @brief Closes all docked widgets.
  195. */
  196. void closeAll();
  197. private:
  198. DockManager(EditorWindowBase* parentWindow, const GUIDimensions& dimensions);
  199. ~DockManager();
  200. static const Color TINT_COLOR;
  201. static const Color HIGHLIGHT_COLOR;
  202. EditorWindowBase* mParentWindow;
  203. DockContainer mRootContainer;
  204. Rect2I mArea;
  205. HMesh mDropOverlayMesh;
  206. HMaterial mDropOverlayMat;
  207. Rect2I mLastOverlayBounds;
  208. DockContainer* mMouseOverContainer;
  209. DockLocation mHighlightedDropLoc;
  210. bool mShowOverlay;
  211. Vector2* mTopDropPolygon;
  212. Vector2* mBotDropPolygon;
  213. Vector2* mLeftDropPolygon;
  214. Vector2* mRightDropPolygon;
  215. HEvent mRenderCallback;
  216. /**
  217. * @brief Render callback that allows the dock manager to render its overlay when needed.
  218. * Called once per frame by the renderer.
  219. */
  220. void render(const Viewport* viewport, DrawList& renderQueue);
  221. /**
  222. * @brief Updates the dock overlay mesh that is displayed when user is dragging a widget
  223. * over a certain area.
  224. */
  225. void updateDropOverlay(INT32 x, INT32 y, UINT32 width, UINT32 height);
  226. /**
  227. * @brief Checks is the provided point inside the provided polygon.
  228. *
  229. * @param polyPoints Points of the polygon to test against.
  230. * @param numPoints Number of points in "polyPoints".
  231. * @param point Point to check if it's in the polygon.
  232. *
  233. * @returns True if the point is in the polygon.
  234. */
  235. bool insidePolygon(Vector2* polyPoints, UINT32 numPoints, Vector2 point) const;
  236. /**
  237. * @copydoc GUIElementBase::updateClippedBounds
  238. */
  239. void updateClippedBounds() override;
  240. /**
  241. * @copydoc GUIElementBase::_mouseEvent
  242. */
  243. bool _mouseEvent(const GUIMouseEvent& event) override;
  244. };
  245. }