BsDockManager.h 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  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 widgetParent GUI widget of the parent dock manager.
  35. * @param parentWindow Editor window of the parent dock manager.
  36. */
  37. void makeLeaf(GUIWidget* widgetParent, EditorWindowBase* parentWindow);
  38. /**
  39. * @brief Transforms the container from non-leaf (parent to other containers)
  40. * to leaf (parent to widgets). Unlike the other overload this one accepts
  41. * a previously created widget container.
  42. *
  43. * @param existingContainer An existing widget container that may be used for docking widgets.
  44. */
  45. void makeLeaf(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. GUIDockSlider* mSlider;
  128. Rect2I mArea;
  129. float mSplitPosition;
  130. bool mIsHorizontal;
  131. static const UINT32 SLIDER_SIZE;
  132. static const UINT32 MIN_CHILD_SIZE;
  133. private:
  134. /**
  135. * @brief Updates sizes and positions of all child containers.
  136. * Normally called when parent area changes.
  137. */
  138. void updateChildAreas();
  139. /**
  140. * @brief Triggered whenever the user drags the GUI slider belonging to this container.
  141. */
  142. void sliderDragged(const Vector2I& delta);
  143. /**
  144. * @brief Triggered whenever the user closes or undocks a widget belonging to this container.
  145. */
  146. void widgetRemoved();
  147. };
  148. /**
  149. * @brief Available dock locations for the dock manager.
  150. */
  151. enum class DockLocation
  152. {
  153. Top,
  154. Bottom,
  155. Left,
  156. Right,
  157. None
  158. };
  159. public:
  160. /**
  161. * @brief Creates a new dock manager for the specified window.
  162. */
  163. static DockManager* create(EditorWindowBase* parentWindow);
  164. /**
  165. * @brief Internal method. Called once every frame.
  166. */
  167. void update();
  168. /**
  169. * @brief Inserts a new widget at the specified location.
  170. *
  171. * @param relativeTo Container relative to which to insert the widget. Can be null in which case
  172. * the widget is inserted at the root.
  173. * @param widgetToInsert Widget we want to insert into the dock layout.
  174. * @param location Location to insert the widget at, relative to "relativeTo" container.
  175. * If "relativeTo" is null this is ignored.
  176. */
  177. void insert(EditorWidgetContainer* relativeTo, EditorWidgetBase* widgetToInsert, DockLocation location);
  178. /**
  179. * @brief Returns a saved layout of all the currently docked widgets and their positions
  180. * and areas.
  181. */
  182. DockManagerLayoutPtr getLayout() const;
  183. /**
  184. * @brief Sets a previously saved layout of docked widgets. This will close all currently active
  185. * widgets and open and position new ones according to the layout.
  186. */
  187. void setLayout(const DockManagerLayoutPtr& layout);
  188. /**
  189. * @brief Changes the position and size of the dock manager.
  190. */
  191. void setArea(INT32 x, INT32 y, UINT32 width, UINT32 height);
  192. /**
  193. * @brief Closes all docked widgets.
  194. */
  195. void closeAll();
  196. private:
  197. DockManager(EditorWindowBase* parentWindow, const GUIDimensions& dimensions);
  198. ~DockManager();
  199. static const Color TINT_COLOR;
  200. static const Color HIGHLIGHT_COLOR;
  201. EditorWindowBase* mParentWindow;
  202. DockContainer mRootContainer;
  203. Rect2I mArea;
  204. HMesh mDropOverlayMesh;
  205. HMaterial mDropOverlayMat;
  206. Rect2I mLastOverlayBounds;
  207. DockContainer* mMouseOverContainer;
  208. DockLocation mHighlightedDropLoc;
  209. bool mShowOverlay;
  210. Vector2* mTopDropPolygon;
  211. Vector2* mBotDropPolygon;
  212. Vector2* mLeftDropPolygon;
  213. Vector2* mRightDropPolygon;
  214. HEvent mRenderCallback;
  215. /**
  216. * @brief Render callback that allows the dock manager to render its overlay when needed.
  217. * Called once per frame by the renderer.
  218. */
  219. void render(const Viewport* viewport, DrawList& renderQueue);
  220. /**
  221. * @brief Updates the dock overlay mesh that is displayed when user is dragging a widget
  222. * over a certain area.
  223. */
  224. void updateDropOverlay(INT32 x, INT32 y, UINT32 width, UINT32 height);
  225. /**
  226. * @brief Checks is the provided point inside the provided polygon.
  227. *
  228. * @param polyPoints Points of the polygon to test against.
  229. * @param numPoints Number of points in "polyPoints".
  230. * @param point Point to check if it's in the polygon.
  231. *
  232. * @returns True if the point is in the polygon.
  233. */
  234. bool insidePolygon(Vector2* polyPoints, UINT32 numPoints, Vector2 point) const;
  235. /**
  236. * @copydoc GUIElementBase::updateClippedBounds
  237. */
  238. void updateClippedBounds() override;
  239. /**
  240. * @copydoc GUIElementBase::_mouseEvent
  241. */
  242. bool _mouseEvent(const GUIMouseEvent& event) override;
  243. };
  244. }