BsDockManager.h 11 KB

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