BsDockManager.h 11 KB

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