BsDockManager.h 12 KB

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