BsDockManager.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. #include "BsDockManager.h"
  2. #include "BsEditorWidgetContainer.h"
  3. #include "CmMath.h"
  4. #include "CmException.h"
  5. #include "CmMesh.h"
  6. #include "CmMaterial.h"
  7. #include "CmVector2.h"
  8. #include "CmRenderQueue.h"
  9. #include "CmApplication.h"
  10. #include "CmRendererManager.h"
  11. #include "CmRenderer.h"
  12. #include "BsBuiltinMaterialManager.h"
  13. #include "BsGUIWidget.h"
  14. #include "BsCamera.h"
  15. using namespace CamelotFramework;
  16. using namespace BansheeEngine;
  17. namespace BansheeEditor
  18. {
  19. const CM::UINT32 DockManager::DockContainer::SliderSize = 4;
  20. const CM::Color DockManager::TINT_COLOR = Color(0.44f, 0.44f, 0.44f, 0.22f);
  21. const CM::Color DockManager::HIGHLIGHT_COLOR = Color(0.44f, 0.44f, 0.44f, 0.42f);
  22. DockManager::DockContainer::DockContainer()
  23. :mIsLeaf(false), mWidgets(nullptr), mX(0), mY(0), mWidth(0), mHeight(0), mSplitPosition(0.5f),
  24. mIsHorizontal(false)
  25. {
  26. mChildren[0] = nullptr;
  27. mChildren[1] = nullptr;
  28. }
  29. DockManager::DockContainer::~DockContainer()
  30. {
  31. if(mIsLeaf && mWidgets != nullptr)
  32. cm_delete(mWidgets);
  33. if(!mIsLeaf)
  34. {
  35. if(mChildren[0] != nullptr)
  36. cm_delete(mChildren[0]);
  37. if(mChildren[1] != nullptr)
  38. cm_delete(mChildren[1]);
  39. }
  40. // TODO - Clean up slider
  41. }
  42. void DockManager::DockContainer::setArea(CM::INT32 x, CM::INT32 y, UINT32 width, UINT32 height)
  43. {
  44. mX = x;
  45. mY = y;
  46. mWidth = width;
  47. mHeight = height;
  48. if(mIsLeaf)
  49. {
  50. if(mWidgets != nullptr)
  51. {
  52. mWidgets->setPosition(x, y);
  53. mWidgets->setSize(width, height);
  54. }
  55. }
  56. else if(mChildren[0] != nullptr && mChildren[1] != nullptr)
  57. {
  58. if(mIsHorizontal)
  59. {
  60. UINT32 remainingSize = (UINT32)std::max(0, (INT32)mHeight - (INT32)SliderSize);
  61. UINT32 sizeTop = Math::FloorToInt(remainingSize * mSplitPosition);
  62. UINT32 sizeBottom = remainingSize - sizeTop;
  63. mChildren[0]->setArea(mX, mY, mWidth, sizeTop);
  64. mChildren[1]->setArea(mX, mY + sizeTop + SliderSize, mWidth, sizeBottom);
  65. // TODO - Set slider position
  66. }
  67. else
  68. {
  69. UINT32 remainingSize = (UINT32)std::max(0, (INT32)mWidth - (INT32)SliderSize);
  70. UINT32 sizeLeft = Math::FloorToInt(remainingSize * mSplitPosition);
  71. UINT32 sizeRight = remainingSize - sizeLeft;
  72. mChildren[0]->setArea(mX, mY, sizeLeft, mHeight);
  73. mChildren[1]->setArea(mX + sizeLeft + SliderSize, mY, sizeRight, mHeight);
  74. // TODO - Set slider position
  75. }
  76. }
  77. }
  78. void DockManager::DockContainer::makeLeaf(GUIWidget* widgetParent, EditorWidget* widget)
  79. {
  80. mIsLeaf = true;
  81. mWidgets = cm_new<EditorWidgetContainer>(widgetParent);
  82. mWidgets->add(*widget);
  83. mWidgets->setPosition(mX, mY);
  84. mWidgets->setSize(mWidth, mHeight);
  85. }
  86. void DockManager::DockContainer::addLeft(BS::GUIWidget* widgetParent, EditorWidget* widget)
  87. {
  88. splitContainer(widgetParent, widget, false, true);
  89. }
  90. void DockManager::DockContainer::addRight(BS::GUIWidget* widgetParent, EditorWidget* widget)
  91. {
  92. splitContainer(widgetParent, widget, false, false);
  93. }
  94. void DockManager::DockContainer::addTop(BS::GUIWidget* widgetParent, EditorWidget* widget)
  95. {
  96. splitContainer(widgetParent, widget, true, true);
  97. }
  98. void DockManager::DockContainer::addBottom(BS::GUIWidget* widgetParent, EditorWidget* widget)
  99. {
  100. splitContainer(widgetParent, widget, true, false);
  101. }
  102. void DockManager::DockContainer::splitContainer(BS::GUIWidget* widgetParent, EditorWidget* widget, bool horizontal, bool newChildIsFirst)
  103. {
  104. UINT32 idxA = newChildIsFirst ? 0 : 1;
  105. UINT32 idxB = (idxA + 1) % 2;
  106. mChildren[idxA] = cm_new<DockContainer>();
  107. mChildren[idxB] = cm_new<DockContainer>(*this);
  108. mChildren[idxA]->makeLeaf(widgetParent, widget);
  109. mIsLeaf = false;
  110. mIsHorizontal = horizontal;
  111. mWidgets = nullptr;
  112. mSplitPosition = 0.5f;
  113. // TODO - Add slider
  114. setArea(mX, mY, mWidth, mHeight);
  115. }
  116. DockManager::DockContainer* DockManager::DockContainer::find(EditorWidgetContainer* widgetContainer)
  117. {
  118. if(mIsLeaf)
  119. {
  120. if(mWidgets == widgetContainer)
  121. return this;
  122. else
  123. return nullptr;
  124. }
  125. else
  126. {
  127. if(mChildren[0] != nullptr && mChildren[0]->find(widgetContainer) != nullptr)
  128. return mChildren[0];
  129. if(mChildren[1] != nullptr && mChildren[1]->find(widgetContainer) != nullptr)
  130. return mChildren[1];
  131. }
  132. return nullptr;
  133. }
  134. DockManager::DockManager(BS::GUIWidget* parent)
  135. :mParent(parent)
  136. {
  137. mDropOverlayMat = BuiltinMaterialManager::instance().createDockDropOverlayMaterial();
  138. RendererManager::instance().getActive()->addRenderCallback(parent->getTarget(), boost::bind(&DockManager::render, this, _1, _2));
  139. }
  140. DockManager::~DockManager()
  141. {
  142. }
  143. void DockManager::render(const Viewport* viewport, CM::RenderQueue& renderQueue)
  144. {
  145. float invViewportWidth = 1.0f / (viewport->getWidth() * 0.5f);
  146. float invViewportHeight = 1.0f / (viewport->getHeight() * 0.5f);
  147. if(mDropOverlayMesh == nullptr || !mDropOverlayMesh.isLoaded() || !mDropOverlayMesh->isInitialized())
  148. return;
  149. if(mDropOverlayMat == nullptr || !mDropOverlayMat.isLoaded() || !mDropOverlayMat->isInitialized())
  150. return;
  151. mDropOverlayMat->setFloat("invViewportWidth", invViewportWidth);
  152. mDropOverlayMat->setFloat("invViewportHeight", invViewportHeight);
  153. mDropOverlayMat->setColor("tintColor", TINT_COLOR);
  154. mDropOverlayMat->setColor("highlightColor", HIGHLIGHT_COLOR);
  155. mDropOverlayMat->setColor("highlightActive", Color(0.0f, 0.0f, 0.0f, 0.0f));
  156. renderQueue.add(mDropOverlayMat, mDropOverlayMesh->getSubMeshData(), Vector3::ZERO);
  157. }
  158. void DockManager::insert(EditorWidgetContainer* relativeTo, EditorWidget* widgetToInsert, DockLocation location)
  159. {
  160. if(relativeTo != nullptr)
  161. {
  162. DockContainer* container = mRootContainer.find(relativeTo);
  163. if(container == nullptr)
  164. CM_EXCEPT(InternalErrorException, "Cannot find the wanted widget container relative to which the widget should be inserted.");
  165. switch(location)
  166. {
  167. case DockLocation::Left:
  168. container->addLeft(mParent, widgetToInsert);
  169. break;
  170. case DockLocation::Right:
  171. container->addRight(mParent, widgetToInsert);
  172. break;
  173. case DockLocation::Top:
  174. container->addTop(mParent, widgetToInsert);
  175. break;
  176. case DockLocation::Bottom:
  177. container->addBottom(mParent, widgetToInsert);
  178. break;
  179. }
  180. }
  181. else
  182. {
  183. if(mRootContainer.mWidgets != nullptr)
  184. CM_EXCEPT(InternalErrorException, "Trying to insert a widget into dock manager root container but one already exists.");
  185. mRootContainer.makeLeaf(mParent, widgetToInsert);
  186. }
  187. }
  188. void DockManager::setArea(INT32 x, INT32 y, UINT32 width, UINT32 height)
  189. {
  190. mRootContainer.setArea(x, y, width, height);
  191. createDropOverlayMesh(x, y, width, height);
  192. }
  193. void DockManager::createDropOverlayMesh(INT32 x, INT32 y, UINT32 width, UINT32 height)
  194. {
  195. const static int spacing = 10;
  196. const static float innerScale = 0.75f;
  197. UINT32 outWidth = std::max(0, (INT32)width - spacing * 2);
  198. UINT32 outHeight = std::max(0, (INT32)height - spacing * 2);
  199. UINT32 inWidth = (UINT32)Math::FloorToInt(innerScale * outWidth);
  200. UINT32 inHeight = (UINT32)Math::FloorToInt(innerScale * outHeight);
  201. INT32 inXOffset = Math::FloorToInt((outWidth - inWidth) * 0.5f);
  202. INT32 inYOffset = Math::FloorToInt((outHeight - inHeight) * 0.5f);
  203. Vector2 outTopLeft((float)x, (float)y);
  204. Vector2 outTopRight((float)(x + outWidth), (float)y);
  205. Vector2 outBotLeft((float)x, (float)(y + outHeight));
  206. Vector2 outBotRight((float)(x + outWidth), (float)(y + outHeight));
  207. Vector2 inTopLeft((float)(x + inXOffset), (float)(y + inYOffset));
  208. Vector2 inTopRight((float)(x + inXOffset + inWidth), (float)(y + inYOffset));
  209. Vector2 inBotLeft((float)(x + inXOffset), (float)(y + inYOffset + inHeight));
  210. Vector2 inBotRight((float)(x + inXOffset + inWidth), (float)(y + inYOffset + inHeight));
  211. MeshDataPtr meshData = cm_shared_ptr<MeshData, ScratchAlloc>(16);
  212. meshData->beginDesc();
  213. meshData->addSubMesh(24, 0, DOT_TRIANGLE_LIST);
  214. meshData->addVertElem(VET_FLOAT2, VES_POSITION);
  215. meshData->addVertElem(VET_COLOR, VES_COLOR);
  216. meshData->endDesc();
  217. auto vertIter = meshData->getVec2DataIter(VES_POSITION);
  218. auto colIter = meshData->getDWORDDataIter(VES_COLOR);
  219. // Top
  220. Vector2 topOffset((float)spacing, 0.0f);
  221. Vector2 dbg = outTopLeft + topOffset;
  222. vertIter.addValue(outTopLeft + topOffset);
  223. vertIter.addValue(outTopRight + topOffset);
  224. vertIter.addValue(inTopRight + topOffset);
  225. vertIter.addValue(inTopLeft + topOffset);
  226. Color color(1.0f, 0.0f, 0.0f, 0.0f);
  227. UINT32 color32 = color.getAsRGBA();
  228. colIter.addValue(color32);
  229. colIter.addValue(color32);
  230. colIter.addValue(color32);
  231. colIter.addValue(color32);
  232. // Bottom
  233. Vector2 botOffset((float)spacing, (float)spacing * 2.0f);
  234. vertIter.addValue(inBotLeft + botOffset);
  235. vertIter.addValue(inBotRight + botOffset);
  236. vertIter.addValue(outBotRight + botOffset);
  237. vertIter.addValue(outBotLeft + botOffset);
  238. color = Color(0.0f, 1.0f, 0.0f, 0.0f);
  239. color32 = color.getAsRGBA();
  240. colIter.addValue(color32);
  241. colIter.addValue(color32);
  242. colIter.addValue(color32);
  243. colIter.addValue(color32);
  244. // Left
  245. Vector2 leftOffset(0.0f, (float)spacing);
  246. vertIter.addValue(outTopLeft + leftOffset);
  247. vertIter.addValue(inTopLeft + leftOffset);
  248. vertIter.addValue(inBotLeft + leftOffset);
  249. vertIter.addValue(outBotLeft + leftOffset);
  250. color = Color(0.0f, 0.0f, 1.0f, 0.0f);
  251. color32 = color.getAsRGBA();
  252. colIter.addValue(color32);
  253. colIter.addValue(color32);
  254. colIter.addValue(color32);
  255. colIter.addValue(color32);
  256. // Right
  257. Vector2 rightOffset((float)spacing * 2.0f, (float)spacing);
  258. vertIter.addValue(inTopRight + rightOffset);
  259. vertIter.addValue(outTopRight + rightOffset);
  260. vertIter.addValue(outBotRight + rightOffset);
  261. vertIter.addValue(inBotRight + rightOffset);
  262. color = Color(0.0f, 0.0f, 0.0f, 1.0f);
  263. color32 = color.getAsRGBA();
  264. colIter.addValue(color32);
  265. colIter.addValue(color32);
  266. colIter.addValue(color32);
  267. colIter.addValue(color32);
  268. UINT32* indexData = meshData->getIndices32();
  269. // Top
  270. indexData[0] = 0;
  271. indexData[1] = 1;
  272. indexData[2] = 2;
  273. indexData[3] = 0;
  274. indexData[4] = 2;
  275. indexData[5] = 3;
  276. // Bottom
  277. indexData[6] = 4;
  278. indexData[7] = 5;
  279. indexData[8] = 6;
  280. indexData[9] = 4;
  281. indexData[10] = 6;
  282. indexData[11] = 7;
  283. // Left
  284. indexData[12] = 8;
  285. indexData[13] = 9;
  286. indexData[14] = 10;
  287. indexData[15] = 8;
  288. indexData[16] = 10;
  289. indexData[17] = 11;
  290. // Right
  291. indexData[18] = 12;
  292. indexData[19] = 13;
  293. indexData[20] = 14;
  294. indexData[21] = 12;
  295. indexData[22] = 14;
  296. indexData[23] = 15;
  297. mDropOverlayMesh = Mesh::create();
  298. gMainSyncedCA().writeSubresource(mDropOverlayMesh.getInternalPtr(), 0, *meshData);
  299. gMainSyncedCA().submitToCoreThread(true);
  300. }
  301. }