BsDockManager.cpp 30 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040
  1. #include "BsDockManager.h"
  2. #include "BsEditorWidgetContainer.h"
  3. #include "BsEditorWidget.h"
  4. #include "BsEditorWidgetManager.h"
  5. #include "BsMath.h"
  6. #include "BsException.h"
  7. #include "BsMesh.h"
  8. #include "BsMaterial.h"
  9. #include "BsVector2.h"
  10. #include "BsDrawList.h"
  11. #include "BsCoreApplication.h"
  12. #include "BsRendererManager.h"
  13. #include "BsCoreRenderer.h"
  14. #include "BsSceneObject.h"
  15. #include "BsGUIManager.h"
  16. #include "BsBuiltinEditorResources.h"
  17. #include "BsGUIWidget.h"
  18. #include "BsCamera.h"
  19. #include "BsDragAndDropManager.h"
  20. #include "BsGUIDockSlider.h"
  21. #include "BsVertexDataDesc.h"
  22. #include "BsGUISkin.h"
  23. #include "BsBuiltinResources.h"
  24. #include "BsDockManagerLayout.h"
  25. #include "BsEditorWindow.h"
  26. #include "BsGUISkin.h"
  27. #include "BsGUIButton.h"
  28. using namespace std::placeholders;
  29. namespace BansheeEngine
  30. {
  31. const UINT32 DockManager::DockContainer::SLIDER_SIZE = 4;
  32. const UINT32 DockManager::DockContainer::MIN_CHILD_SIZE = 20;
  33. const Color DockManager::TINT_COLOR = Color(0.44f, 0.44f, 0.44f, 0.22f);
  34. const Color DockManager::HIGHLIGHT_COLOR = Color(0.44f, 0.44f, 0.44f, 0.42f);
  35. DockManager::DockContainer::DockContainer(DockManager* manager)
  36. :mIsLeaf(true), mWidgets(nullptr), mSplitPosition(0.5f),
  37. mIsHorizontal(false), mParent(nullptr), mSlider(nullptr), mManager(manager)
  38. {
  39. mChildren[0] = nullptr;
  40. mChildren[1] = nullptr;
  41. }
  42. DockManager::DockContainer::DockContainer(DockManager* manager, DockContainer* parent)
  43. :mIsLeaf(false), mWidgets(nullptr), mSplitPosition(0.5f),
  44. mIsHorizontal(false), mParent(parent), mSlider(nullptr), mManager(manager)
  45. {
  46. mChildren[0] = nullptr;
  47. mChildren[1] = nullptr;
  48. }
  49. DockManager::DockContainer::~DockContainer()
  50. {
  51. if(mIsLeaf && mWidgets != nullptr)
  52. bs_delete(mWidgets);
  53. if(!mIsLeaf)
  54. {
  55. if(mChildren[0] != nullptr)
  56. bs_delete(mChildren[0]);
  57. if(mChildren[1] != nullptr)
  58. bs_delete(mChildren[1]);
  59. }
  60. if(mSlider != nullptr)
  61. {
  62. GUIElement::destroy(mSlider);
  63. mSlider = nullptr;
  64. }
  65. }
  66. void DockManager::DockContainer::setArea(INT32 x, INT32 y, UINT32 width, UINT32 height)
  67. {
  68. if(mIsLeaf)
  69. {
  70. if(mWidgets != nullptr)
  71. {
  72. mWidgets->setPosition(x, y);
  73. mWidgets->setSize(width, height);
  74. }
  75. }
  76. mArea.x = x;
  77. mArea.y = y;
  78. mArea.width = width;
  79. mArea.height = height;
  80. updateChildAreas();
  81. }
  82. void DockManager::DockContainer::updateChildAreas()
  83. {
  84. if(!mIsLeaf && mChildren[0] != nullptr && mChildren[1] != nullptr)
  85. {
  86. Rect2I clipRect = mArea;
  87. if(mIsHorizontal)
  88. {
  89. UINT32 remainingSize = (UINT32)std::max(0, (INT32)mArea.height - (INT32)SLIDER_SIZE);
  90. UINT32 sizeTop = Math::floorToInt(remainingSize * mSplitPosition);
  91. UINT32 sizeBottom = remainingSize - sizeTop;
  92. mChildren[0]->setArea(mArea.x, mArea.y, mArea.width, sizeTop);
  93. mChildren[1]->setArea(mArea.x, mArea.y + sizeTop + SLIDER_SIZE, mArea.width, sizeBottom);
  94. mSlider->_setPosition(Vector2I(mArea.x, mArea.y + sizeTop));
  95. mSlider->_setWidth(mArea.width);
  96. mSlider->_setHeight(SLIDER_SIZE);
  97. Rect2I elemClipRect(clipRect.x - mArea.x, clipRect.y - mArea.y, clipRect.width, clipRect.height);
  98. mSlider->_setClipRect(elemClipRect);
  99. mSlider->markContentAsDirty();
  100. }
  101. else
  102. {
  103. UINT32 remainingSize = (UINT32)std::max(0, (INT32)mArea.width - (INT32)SLIDER_SIZE);
  104. UINT32 sizeLeft = Math::floorToInt(remainingSize * mSplitPosition);
  105. UINT32 sizeRight = remainingSize - sizeLeft;
  106. mChildren[0]->setArea(mArea.x, mArea.y, sizeLeft, mArea.height);
  107. mChildren[1]->setArea(mArea.x + sizeLeft + SLIDER_SIZE, mArea.y, sizeRight, mArea.height);
  108. mSlider->_setPosition(Vector2I(mArea.x + sizeLeft, mArea.y));
  109. mSlider->_setWidth(SLIDER_SIZE);
  110. mSlider->_setHeight(mArea.height);
  111. Rect2I elemClipRect(clipRect.x - mArea.x, clipRect.y - mArea.y, clipRect.width, clipRect.height);
  112. mSlider->_setClipRect(elemClipRect);
  113. mSlider->markContentAsDirty();
  114. }
  115. }
  116. }
  117. void DockManager::DockContainer::makeLeaf(GUIWidget* widgetParent, EditorWindowBase* parentWindow)
  118. {
  119. mIsLeaf = true;
  120. mWidgets = bs_new<EditorWidgetContainer>(widgetParent, parentWindow);
  121. mWidgets->onWidgetClosed.connect(std::bind(&DockManager::DockContainer::widgetRemoved, this));
  122. if(mSlider != nullptr)
  123. {
  124. GUIElement::destroy(mSlider);
  125. mSlider = nullptr;
  126. }
  127. mWidgets->setPosition(mArea.x, mArea.y);
  128. mWidgets->setSize(mArea.width, mArea.height);
  129. }
  130. void DockManager::DockContainer::makeLeaf(EditorWidgetContainer* existingContainer)
  131. {
  132. mIsLeaf = true;
  133. mWidgets = existingContainer;
  134. mWidgets->onWidgetClosed.connect(std::bind(&DockManager::DockContainer::widgetRemoved, this));
  135. if(mSlider != nullptr)
  136. {
  137. GUIElement::destroy(mSlider);
  138. mSlider = nullptr;
  139. }
  140. mWidgets->setPosition(mArea.x, mArea.y);
  141. mWidgets->setSize(mArea.width, mArea.height);
  142. }
  143. void DockManager::DockContainer::addLeft(EditorWidgetBase* widget)
  144. {
  145. if(mIsLeaf)
  146. splitContainer(false, true);
  147. mChildren[0]->addWidget(widget);
  148. }
  149. void DockManager::DockContainer::addRight(EditorWidgetBase* widget)
  150. {
  151. if(mIsLeaf)
  152. splitContainer(false, false);
  153. mChildren[1]->addWidget(widget);
  154. }
  155. void DockManager::DockContainer::addTop(EditorWidgetBase* widget)
  156. {
  157. if(mIsLeaf)
  158. splitContainer(true, true);
  159. mChildren[0]->addWidget(widget);
  160. }
  161. void DockManager::DockContainer::addBottom(EditorWidgetBase* widget)
  162. {
  163. if(mIsLeaf)
  164. splitContainer(true, false);
  165. mChildren[1]->addWidget(widget);
  166. }
  167. void DockManager::DockContainer::splitContainer(bool horizontal, bool newChildIsFirst, float splitPosition)
  168. {
  169. DockContainer* children[2];
  170. UINT32 idxA = newChildIsFirst ? 0 : 1;
  171. UINT32 idxB = (idxA + 1) % 2;
  172. children[idxA] = bs_new<DockContainer>(mManager, this);
  173. children[idxB] = bs_new<DockContainer>(mManager, this);
  174. mWidgets->onWidgetClosed.clear();
  175. children[idxA]->makeLeaf(mManager->_getParentWidget(), mManager->mParentWindow);
  176. children[idxB]->makeLeaf(mWidgets);
  177. mWidgets = nullptr;
  178. makeSplit(mManager->_getParentWidget(), children[0], children[1], horizontal, splitPosition);
  179. }
  180. void DockManager::DockContainer::makeSplit(GUIWidget* widgetParent, DockManager::DockContainer* first, DockManager::DockContainer* second, bool horizontal, float splitPosition)
  181. {
  182. mChildren[0] = first;
  183. mChildren[1] = second;
  184. mIsLeaf = false;
  185. mIsHorizontal = horizontal;
  186. mSplitPosition = splitPosition;
  187. if (mWidgets != nullptr)
  188. {
  189. bs_delete(mWidgets);
  190. mWidgets = nullptr;
  191. }
  192. if (mSlider != nullptr)
  193. {
  194. GUIElement::destroy(mSlider);
  195. mSlider = nullptr;
  196. }
  197. if (horizontal)
  198. {
  199. mSlider = GUIDockSlider::create(true, "DockSliderBtn");
  200. mSlider->_setWidgetDepth(widgetParent->getDepth());
  201. mSlider->markMeshAsDirty();
  202. }
  203. else
  204. {
  205. mSlider = GUIDockSlider::create(false, "DockSliderBtn");
  206. mSlider->_setWidgetDepth(widgetParent->getDepth());
  207. mSlider->markMeshAsDirty();
  208. }
  209. mSlider->_changeParentWidget(widgetParent);
  210. mSlider->onDragged.connect(std::bind(&DockManager::DockContainer::sliderDragged, this, _1));
  211. setArea(mArea.x, mArea.y, mArea.width, mArea.height);
  212. }
  213. void DockManager::DockContainer::addWidget(EditorWidgetBase* widget)
  214. {
  215. if(!mIsLeaf)
  216. return;
  217. mWidgets->add(*widget);
  218. }
  219. void DockManager::DockContainer::addWidget(const String& name)
  220. {
  221. if(!mIsLeaf)
  222. return;
  223. EditorWidgetManager::instance().create(name, *mWidgets);
  224. }
  225. void DockManager::DockContainer::sliderDragged(const Vector2I& delta)
  226. {
  227. if(mIsHorizontal && delta.y != 0)
  228. {
  229. UINT32 maxSize = (UINT32)std::max(MIN_CHILD_SIZE, (INT32)mArea.height - (INT32)SLIDER_SIZE - MIN_CHILD_SIZE);
  230. UINT32 remainingSize = (UINT32)std::max(0, (INT32)mArea.height - (INT32)SLIDER_SIZE);
  231. mSplitPosition = Math::clamp((UINT32)Math::floorToInt(remainingSize * mSplitPosition) + delta.y, MIN_CHILD_SIZE, maxSize) / (float)remainingSize;
  232. updateChildAreas();
  233. }
  234. else if(!mIsHorizontal && delta.x != 0)
  235. {
  236. UINT32 maxSize = (UINT32)std::max(MIN_CHILD_SIZE, (INT32)mArea.width - (INT32)SLIDER_SIZE - MIN_CHILD_SIZE);
  237. UINT32 remainingSize = (UINT32)std::max(0, (INT32)mArea.width - (INT32)SLIDER_SIZE);
  238. mSplitPosition = Math::clamp((UINT32)Math::floorToInt(remainingSize * mSplitPosition) + delta.x, MIN_CHILD_SIZE, maxSize) / (float)remainingSize;
  239. updateChildAreas();
  240. }
  241. }
  242. void DockManager::DockContainer::widgetRemoved()
  243. {
  244. assert(mIsLeaf);
  245. if(mWidgets->getNumWidgets() == 0)
  246. {
  247. if(mParent == nullptr) // We're root so we just reset ourselves, can't delete root
  248. {
  249. bs_delete(mWidgets);
  250. mWidgets = nullptr;
  251. mIsLeaf = false;
  252. mSplitPosition = 0.5f;
  253. mIsHorizontal = false;
  254. }
  255. else
  256. {
  257. // Replace our parent with our sibling
  258. DockContainer* sibling = nullptr;
  259. if(mParent->mChildren[0] == this)
  260. sibling = mParent->mChildren[1];
  261. else
  262. sibling = mParent->mChildren[0];
  263. if (sibling->mIsLeaf)
  264. {
  265. sibling->mWidgets->onWidgetClosed.clear();
  266. mParent->makeLeaf(sibling->mWidgets);
  267. sibling->mWidgets = nullptr;
  268. }
  269. else
  270. {
  271. mParent->makeSplit(mManager->_getParentWidget(), sibling->mChildren[0], sibling->mChildren[1], sibling->mIsHorizontal, sibling->mSplitPosition);
  272. sibling->mChildren[0]->mParent = mParent;
  273. sibling->mChildren[1]->mParent = mParent;
  274. sibling->mChildren[0] = nullptr;
  275. sibling->mChildren[1] = nullptr;
  276. }
  277. bs_delete(sibling);
  278. bs_delete(this);
  279. }
  280. }
  281. }
  282. DockManager::DockContainer* DockManager::DockContainer::find(EditorWidgetContainer* widgetContainer)
  283. {
  284. if(mIsLeaf)
  285. {
  286. if(mWidgets == widgetContainer)
  287. return this;
  288. else
  289. return nullptr;
  290. }
  291. else
  292. {
  293. if(mChildren[0] != nullptr && mChildren[0]->find(widgetContainer) != nullptr)
  294. return mChildren[0];
  295. if(mChildren[1] != nullptr && mChildren[1]->find(widgetContainer) != nullptr)
  296. return mChildren[1];
  297. }
  298. return nullptr;
  299. }
  300. DockManager::DockContainer* DockManager::DockContainer::findAtPos(const Vector2I& pos)
  301. {
  302. if(mIsLeaf)
  303. {
  304. if(mArea.contains(pos))
  305. {
  306. return this;
  307. }
  308. }
  309. else
  310. {
  311. if(mChildren[0] != nullptr && mChildren[0]->findAtPos(pos) != nullptr)
  312. return mChildren[0];
  313. if(mChildren[1] != nullptr && mChildren[1]->findAtPos(pos) != nullptr)
  314. return mChildren[1];
  315. }
  316. return nullptr;
  317. }
  318. Rect2I DockManager::DockContainer::getContentBounds() const
  319. {
  320. if(!mIsLeaf || mWidgets == nullptr)
  321. return mArea;
  322. return mWidgets->getContentBounds();
  323. }
  324. void DockManager::DockContainer::update()
  325. {
  326. if (mIsLeaf)
  327. {
  328. if (mWidgets != nullptr)
  329. mWidgets->update();
  330. }
  331. else
  332. {
  333. if (mChildren[0] != nullptr)
  334. mChildren[0]->update();
  335. if (mChildren[1] != nullptr)
  336. mChildren[1]->update();
  337. }
  338. }
  339. DockManager::DockManager(EditorWindowBase* parentWindow, const GUIDimensions& dimensions)
  340. :GUIElementContainer(dimensions), mMouseOverContainer(nullptr), mHighlightedDropLoc(DockLocation::None),
  341. mShowOverlay(false), mRootContainer(this), mParentWindow(parentWindow)
  342. {
  343. mTopDropPolygon = bs_newN<Vector2>(4);
  344. mBotDropPolygon = bs_newN<Vector2>(4);
  345. mLeftDropPolygon = bs_newN<Vector2>(4);
  346. mRightDropPolygon = bs_newN<Vector2>(4);
  347. mDropOverlayMat = BuiltinEditorResources::instance().createDockDropOverlayMaterial();
  348. mRenderCallback = RendererManager::instance().getActive()->onRenderViewport.connect(std::bind(&DockManager::render, this, _1, _2));
  349. }
  350. DockManager::~DockManager()
  351. {
  352. mRenderCallback.disconnect();
  353. bs_deleteN(mTopDropPolygon, 4);
  354. bs_deleteN(mBotDropPolygon, 4);
  355. bs_deleteN(mLeftDropPolygon, 4);
  356. bs_deleteN(mRightDropPolygon, 4);
  357. }
  358. DockManager* DockManager::create(EditorWindowBase* parentWindow)
  359. {
  360. return new (bs_alloc<DockManager, PoolAlloc>()) DockManager(parentWindow, GUIDimensions::create());
  361. }
  362. void DockManager::update()
  363. {
  364. if(!DragAndDropManager::instance().isDragInProgress())
  365. {
  366. mHighlightedDropLoc = DockLocation::None;
  367. mShowOverlay = false;
  368. }
  369. mRootContainer.update();
  370. }
  371. void DockManager::render(const Viewport* viewport, DrawList& drawList)
  372. {
  373. if (_getParentWidget() == nullptr || _getParentWidget()->getTarget() != viewport)
  374. return;
  375. if(!mShowOverlay)
  376. return;
  377. float invViewportWidth = 1.0f / (viewport->getWidth() * 0.5f);
  378. float invViewportHeight = 1.0f / (viewport->getHeight() * 0.5f);
  379. if(!mDropOverlayMesh.isLoaded())
  380. return;
  381. if(!mDropOverlayMat.isLoaded())
  382. return;
  383. mDropOverlayMat->setFloat("invViewportWidth", invViewportWidth);
  384. mDropOverlayMat->setFloat("invViewportHeight", invViewportHeight);
  385. mDropOverlayMat->setColor("tintColor", TINT_COLOR);
  386. mDropOverlayMat->setColor("highlightColor", HIGHLIGHT_COLOR);
  387. Color highlightColor;
  388. switch(mHighlightedDropLoc)
  389. {
  390. case DockLocation::Top:
  391. highlightColor = Color(1.0f, 0.0f, 0.0f, 0.0f);
  392. break;
  393. case DockLocation::Bottom:
  394. highlightColor = Color(0.0f, 1.0f, 0.0f, 0.0f);
  395. break;
  396. case DockLocation::Left:
  397. highlightColor = Color(0.0f, 0.0f, 1.0f, 0.0f);
  398. break;
  399. case DockLocation::Right:
  400. highlightColor = Color(0.0f, 0.0f, 0.0f, 1.0f);
  401. break;
  402. case DockLocation::None:
  403. highlightColor = Color(0.0f, 0.0f, 0.0f, 0.0f);
  404. break;
  405. }
  406. mDropOverlayMat->setColor("highlightActive", highlightColor);
  407. drawList.add(mDropOverlayMat.getInternalPtr(), mDropOverlayMesh.getInternalPtr(), 0, Vector3::ZERO);
  408. }
  409. void DockManager::insert(EditorWidgetContainer* relativeTo, EditorWidgetBase* widgetToInsert, DockLocation location)
  410. {
  411. if(relativeTo != nullptr)
  412. {
  413. DockContainer* container = mRootContainer.find(relativeTo);
  414. if(container == nullptr)
  415. BS_EXCEPT(InternalErrorException, "Cannot find the wanted widget container relative to which the widget should be inserted.");
  416. switch(location)
  417. {
  418. case DockLocation::Left:
  419. container->addLeft(widgetToInsert);
  420. break;
  421. case DockLocation::Right:
  422. container->addRight(widgetToInsert);
  423. break;
  424. case DockLocation::Top:
  425. container->addTop(widgetToInsert);
  426. break;
  427. case DockLocation::Bottom:
  428. container->addBottom(widgetToInsert);
  429. break;
  430. }
  431. }
  432. else
  433. {
  434. if(mRootContainer.mWidgets != nullptr)
  435. BS_EXCEPT(InternalErrorException, "Trying to insert a widget into dock manager root container but one already exists.");
  436. mRootContainer.makeLeaf(_getParentWidget(), mParentWindow);
  437. mRootContainer.addWidget(widgetToInsert);
  438. }
  439. }
  440. void DockManager::setArea(INT32 x, INT32 y, UINT32 width, UINT32 height)
  441. {
  442. mRootContainer.setArea(x, y, width, height);
  443. mArea = Rect2I(x, y, width, height);
  444. updateDropOverlay(x, y, width, height);
  445. }
  446. void DockManager::closeAll()
  447. {
  448. mRootContainer = DockContainer(this);
  449. mMouseOverContainer = nullptr;
  450. }
  451. DockManagerLayoutPtr DockManager::getLayout() const
  452. {
  453. struct StackElem
  454. {
  455. StackElem(DockManagerLayout::Entry* layoutEntry, const DockContainer* container)
  456. :layoutEntry(layoutEntry), container(container)
  457. { }
  458. DockManagerLayout::Entry* layoutEntry;
  459. const DockContainer* container;
  460. };
  461. auto GetWidgetNamesInContainer = [&] (const DockContainer* container)
  462. {
  463. Vector<String> widgetNames;
  464. if(container->mWidgets != nullptr)
  465. {
  466. UINT32 numWidgets = container->mWidgets->getNumWidgets();
  467. for(UINT32 i = 0; i < numWidgets; i++)
  468. {
  469. EditorWidgetBase* widget = container->mWidgets->getWidget(i);
  470. widgetNames.push_back(widget->getName());
  471. }
  472. }
  473. return widgetNames;
  474. };
  475. DockManagerLayoutPtr layout = bs_shared_ptr<DockManagerLayout>();
  476. DockManagerLayout::Entry* rootEntry = &layout->getRootEntry();
  477. if(mRootContainer.mIsLeaf)
  478. {
  479. rootEntry->isLeaf = true;
  480. rootEntry->widgetNames = GetWidgetNamesInContainer(&mRootContainer);
  481. }
  482. else
  483. {
  484. rootEntry->isLeaf = false;
  485. rootEntry->horizontalSplit = mRootContainer.mIsHorizontal;
  486. rootEntry->splitPosition = mRootContainer.mSplitPosition;
  487. rootEntry->parent = nullptr;
  488. }
  489. Stack<StackElem> todo;
  490. todo.push(StackElem(rootEntry, &mRootContainer));
  491. while(!todo.empty())
  492. {
  493. StackElem currentElem = todo.top();
  494. todo.pop();
  495. if(!currentElem.container->mIsLeaf)
  496. {
  497. for(UINT32 i = 0; i < 2; i++)
  498. {
  499. if(currentElem.container->mChildren[i] == nullptr)
  500. continue;
  501. if(currentElem.container->mChildren[i]->mIsLeaf)
  502. {
  503. Vector<String> widgetNames = GetWidgetNamesInContainer(currentElem.container->mChildren[i]);
  504. currentElem.layoutEntry->children[i] =
  505. DockManagerLayout::Entry::createLeaf(currentElem.layoutEntry, i, widgetNames);
  506. }
  507. else
  508. {
  509. currentElem.layoutEntry->children[i] =
  510. DockManagerLayout::Entry::createContainer(currentElem.layoutEntry, i,
  511. currentElem.container->mChildren[i]->mSplitPosition,
  512. currentElem.container->mChildren[i]->mIsHorizontal);
  513. todo.push(StackElem(currentElem.layoutEntry->children[i], currentElem.container->mChildren[i]));
  514. }
  515. }
  516. }
  517. }
  518. return layout;
  519. }
  520. void DockManager::setLayout(const DockManagerLayoutPtr& layout)
  521. {
  522. // Undock all currently docked widgets
  523. Vector<EditorWidgetBase*> undockedWidgets;
  524. Stack<DockContainer*> todo;
  525. todo.push(&mRootContainer);
  526. while(!todo.empty())
  527. {
  528. DockContainer* current = todo.top();
  529. todo.pop();
  530. if(current->mIsLeaf)
  531. {
  532. if(current->mWidgets != nullptr)
  533. {
  534. while(current->mWidgets->getNumWidgets() > 0)
  535. {
  536. EditorWidgetBase* curWidget = current->mWidgets->getWidget(0);
  537. current->mWidgets->remove(*curWidget);
  538. undockedWidgets.push_back(curWidget);
  539. }
  540. }
  541. }
  542. else
  543. {
  544. todo.push(current->mChildren[0]);
  545. todo.push(current->mChildren[1]);
  546. }
  547. }
  548. mRootContainer = DockContainer(this);
  549. // Load layout
  550. struct StackEntry
  551. {
  552. StackEntry(const DockManagerLayout::Entry* layoutEntry, DockContainer* container)
  553. :layoutEntry(layoutEntry), container(container)
  554. { }
  555. const DockManagerLayout::Entry* layoutEntry;
  556. DockContainer* container;
  557. };
  558. auto GetLeafEntry = [] (const DockManagerLayout::Entry* parentEntry, UINT32 childIdx) -> const DockManagerLayout::Entry*
  559. {
  560. while(true)
  561. {
  562. if(parentEntry->isLeaf)
  563. return parentEntry;
  564. parentEntry = parentEntry->children[childIdx];
  565. }
  566. return nullptr;
  567. };
  568. auto OpenWidgets = [&] (DockContainer* parent, const Vector<String>& widgetNames)
  569. {
  570. for(auto& widgetName : widgetNames)
  571. {
  572. parent->addWidget(widgetName);
  573. }
  574. };
  575. // Prune layout by removing invalid leafs (ones with no widgets, or widgets that no longer exist)
  576. layout->pruneInvalidLeaves();
  577. // Dock elements
  578. const DockManagerLayout::Entry* rootEntry = &layout->getRootEntry();
  579. const DockManagerLayout::Entry* leafEntry = GetLeafEntry(rootEntry, 0);
  580. if(leafEntry->widgetNames.size() > 0) // If zero, entire layout is empty
  581. {
  582. mRootContainer.makeLeaf(_getParentWidget(), mParentWindow);
  583. OpenWidgets(&mRootContainer, leafEntry->widgetNames);
  584. if(!rootEntry->isLeaf)
  585. {
  586. Stack<StackEntry> layoutTodo;
  587. layoutTodo.push(StackEntry(rootEntry, &mRootContainer));
  588. while(!layoutTodo.empty())
  589. {
  590. StackEntry curEntry = layoutTodo.top();
  591. layoutTodo.pop();
  592. leafEntry = GetLeafEntry(curEntry.layoutEntry->children[1], 0);
  593. curEntry.container->splitContainer(curEntry.layoutEntry->horizontalSplit, false, curEntry.layoutEntry->splitPosition);
  594. DockContainer* otherChild = curEntry.container->mChildren[1];
  595. OpenWidgets(otherChild, leafEntry->widgetNames);
  596. if(!curEntry.layoutEntry->children[0]->isLeaf)
  597. layoutTodo.push(StackEntry(curEntry.layoutEntry->children[0], curEntry.container->mChildren[0]));
  598. if(!curEntry.layoutEntry->children[1]->isLeaf)
  599. layoutTodo.push(StackEntry(curEntry.layoutEntry->children[1], curEntry.container->mChildren[1]));
  600. }
  601. }
  602. }
  603. // Set container sizes
  604. {
  605. Stack<StackEntry> layoutTodo;
  606. layoutTodo.push(StackEntry(rootEntry, &mRootContainer));
  607. while(!layoutTodo.empty())
  608. {
  609. StackEntry curEntry = layoutTodo.top();
  610. layoutTodo.pop();
  611. if(!curEntry.layoutEntry->isLeaf)
  612. {
  613. layoutTodo.push(StackEntry(curEntry.layoutEntry->children[0], curEntry.container->mChildren[0]));
  614. layoutTodo.push(StackEntry(curEntry.layoutEntry->children[1], curEntry.container->mChildren[1]));
  615. }
  616. }
  617. }
  618. // Destroy any widgets that are no longer docked anywhere
  619. for(auto& widget : undockedWidgets)
  620. {
  621. if(widget->_getParent() == nullptr)
  622. widget->close();
  623. }
  624. setArea(mArea.x, mArea.y, mArea.width, mArea.height);
  625. }
  626. void DockManager::updateClippedBounds()
  627. {
  628. // TODO - Clipping not actually accounted for but shouldn't matter as right now DockManager is only used in one specific situation
  629. mClippedBounds = mRootContainer.mArea;
  630. }
  631. void DockManager::updateDropOverlay(INT32 x, INT32 y, UINT32 width, UINT32 height)
  632. {
  633. const static int spacing = 10;
  634. const static float innerScale = 0.75f;
  635. UINT32 outWidth = std::max(0, (INT32)width - spacing * 2);
  636. UINT32 outHeight = std::max(0, (INT32)height - spacing * 2);
  637. UINT32 inWidth = (UINT32)Math::floorToInt(innerScale * outWidth);
  638. UINT32 inHeight = (UINT32)Math::floorToInt(innerScale * outHeight);
  639. INT32 inXOffset = Math::floorToInt((outWidth - inWidth) * 0.5f);
  640. INT32 inYOffset = Math::floorToInt((outHeight - inHeight) * 0.5f);
  641. Vector2 outTopLeft((float)x, (float)y);
  642. Vector2 outTopRight((float)(x + outWidth), (float)y);
  643. Vector2 outBotLeft((float)x, (float)(y + outHeight));
  644. Vector2 outBotRight((float)(x + outWidth), (float)(y + outHeight));
  645. Vector2 inTopLeft((float)(x + inXOffset), (float)(y + inYOffset));
  646. Vector2 inTopRight((float)(x + inXOffset + inWidth), (float)(y + inYOffset));
  647. Vector2 inBotLeft((float)(x + inXOffset), (float)(y + inYOffset + inHeight));
  648. Vector2 inBotRight((float)(x + inXOffset + inWidth), (float)(y + inYOffset + inHeight));
  649. VertexDataDescPtr vertexDesc = bs_shared_ptr<VertexDataDesc>();
  650. vertexDesc->addVertElem(VET_FLOAT2, VES_POSITION);
  651. vertexDesc->addVertElem(VET_COLOR, VES_COLOR);
  652. MeshDataPtr meshData = bs_shared_ptr<MeshData, ScratchAlloc>(16, 24, vertexDesc);
  653. auto vertIter = meshData->getVec2DataIter(VES_POSITION);
  654. auto colIter = meshData->getDWORDDataIter(VES_COLOR);
  655. // Top
  656. Vector2 topOffset((float)spacing, 0.0f);
  657. mTopDropPolygon[0] = outTopLeft + topOffset;
  658. mTopDropPolygon[1] = outTopRight + topOffset;
  659. mTopDropPolygon[2] = inTopRight + topOffset;
  660. mTopDropPolygon[3] = inTopLeft + topOffset;
  661. vertIter.addValue(mTopDropPolygon[0]);
  662. vertIter.addValue(mTopDropPolygon[1]);
  663. vertIter.addValue(mTopDropPolygon[2]);
  664. vertIter.addValue(mTopDropPolygon[3]);
  665. Color color(1.0f, 0.0f, 0.0f, 0.0f);
  666. UINT32 color32 = color.getAsRGBA();
  667. colIter.addValue(color32);
  668. colIter.addValue(color32);
  669. colIter.addValue(color32);
  670. colIter.addValue(color32);
  671. // Bottom
  672. Vector2 botOffset((float)spacing, (float)spacing * 2.0f);
  673. mBotDropPolygon[0] = inBotLeft + botOffset;
  674. mBotDropPolygon[1] = inBotRight + botOffset;
  675. mBotDropPolygon[2] = outBotRight + botOffset;
  676. mBotDropPolygon[3] = outBotLeft + botOffset;
  677. vertIter.addValue(mBotDropPolygon[0]);
  678. vertIter.addValue(mBotDropPolygon[1]);
  679. vertIter.addValue(mBotDropPolygon[2]);
  680. vertIter.addValue(mBotDropPolygon[3]);
  681. color = Color(0.0f, 1.0f, 0.0f, 0.0f);
  682. color32 = color.getAsRGBA();
  683. colIter.addValue(color32);
  684. colIter.addValue(color32);
  685. colIter.addValue(color32);
  686. colIter.addValue(color32);
  687. // Left
  688. Vector2 leftOffset(0.0f, (float)spacing);
  689. mLeftDropPolygon[0] = outTopLeft + leftOffset;
  690. mLeftDropPolygon[1] = inTopLeft + leftOffset;
  691. mLeftDropPolygon[2] = inBotLeft + leftOffset;
  692. mLeftDropPolygon[3] = outBotLeft + leftOffset;
  693. vertIter.addValue(mLeftDropPolygon[0]);
  694. vertIter.addValue(mLeftDropPolygon[1]);
  695. vertIter.addValue(mLeftDropPolygon[2]);
  696. vertIter.addValue(mLeftDropPolygon[3]);
  697. color = Color(0.0f, 0.0f, 1.0f, 0.0f);
  698. color32 = color.getAsRGBA();
  699. colIter.addValue(color32);
  700. colIter.addValue(color32);
  701. colIter.addValue(color32);
  702. colIter.addValue(color32);
  703. // Right
  704. Vector2 rightOffset((float)spacing * 2.0f, (float)spacing);
  705. mRightDropPolygon[0] = inTopRight + rightOffset;
  706. mRightDropPolygon[1] = outTopRight + rightOffset;
  707. mRightDropPolygon[2] = outBotRight + rightOffset;
  708. mRightDropPolygon[3] = inBotRight + rightOffset;
  709. vertIter.addValue(mRightDropPolygon[0]);
  710. vertIter.addValue(mRightDropPolygon[1]);
  711. vertIter.addValue(mRightDropPolygon[2]);
  712. vertIter.addValue(mRightDropPolygon[3]);
  713. color = Color(0.0f, 0.0f, 0.0f, 1.0f);
  714. color32 = color.getAsRGBA();
  715. colIter.addValue(color32);
  716. colIter.addValue(color32);
  717. colIter.addValue(color32);
  718. colIter.addValue(color32);
  719. UINT32* indexData = meshData->getIndices32();
  720. // Top
  721. indexData[0] = 0;
  722. indexData[1] = 1;
  723. indexData[2] = 2;
  724. indexData[3] = 0;
  725. indexData[4] = 2;
  726. indexData[5] = 3;
  727. // Bottom
  728. indexData[6] = 4;
  729. indexData[7] = 5;
  730. indexData[8] = 6;
  731. indexData[9] = 4;
  732. indexData[10] = 6;
  733. indexData[11] = 7;
  734. // Left
  735. indexData[12] = 8;
  736. indexData[13] = 9;
  737. indexData[14] = 10;
  738. indexData[15] = 8;
  739. indexData[16] = 10;
  740. indexData[17] = 11;
  741. // Right
  742. indexData[18] = 12;
  743. indexData[19] = 13;
  744. indexData[20] = 14;
  745. indexData[21] = 12;
  746. indexData[22] = 14;
  747. indexData[23] = 15;
  748. mDropOverlayMesh = Mesh::create(meshData);
  749. }
  750. bool DockManager::_mouseEvent(const GUIMouseEvent& event)
  751. {
  752. if(event.getType() == GUIMouseEventType::MouseDragAndDropDragged)
  753. {
  754. if(DragAndDropManager::instance().getDragTypeId() != (UINT32)DragAndDropType::EditorWidget)
  755. return false;
  756. const Vector2I& widgetRelPos = event.getPosition();
  757. const Matrix4& worldTfrm = _getParentWidget()->SO()->getWorldTfrm();
  758. Vector4 tfrmdPos = worldTfrm.multiplyAffine(Vector4((float)widgetRelPos.x, (float)widgetRelPos.y, 0.0f, 1.0f));
  759. Vector2 windowPosVec(tfrmdPos.x, tfrmdPos.y);
  760. Vector2I windowPos(Math::roundToInt(windowPosVec.x), Math::roundToInt(windowPosVec.y));
  761. mMouseOverContainer = mRootContainer.findAtPos(windowPos);
  762. if(mMouseOverContainer == nullptr)
  763. mMouseOverContainer = &mRootContainer;
  764. Rect2I overlayBounds;
  765. if(mMouseOverContainer != nullptr)
  766. overlayBounds = mMouseOverContainer->getContentBounds();
  767. // Update mesh if needed
  768. if(mLastOverlayBounds != overlayBounds)
  769. {
  770. if(overlayBounds.width <= 0 || overlayBounds.height <= 0)
  771. mDropOverlayMesh = HMesh();
  772. else
  773. updateDropOverlay(overlayBounds.x, overlayBounds.y, overlayBounds.width, overlayBounds.height);
  774. mLastOverlayBounds = overlayBounds;
  775. }
  776. // Check if we need to highlight any drop locations
  777. if(mMouseOverContainer != nullptr)
  778. {
  779. if(insidePolygon(mTopDropPolygon, 4, windowPosVec))
  780. mHighlightedDropLoc = DockLocation::Top;
  781. else if(insidePolygon(mBotDropPolygon, 4, windowPosVec))
  782. mHighlightedDropLoc = DockLocation::Bottom;
  783. else if(insidePolygon(mLeftDropPolygon, 4, windowPosVec))
  784. mHighlightedDropLoc = DockLocation::Left;
  785. else if(insidePolygon(mRightDropPolygon, 4, windowPosVec))
  786. mHighlightedDropLoc = DockLocation::Right;
  787. else
  788. mHighlightedDropLoc = DockLocation::None;
  789. if(overlayBounds.contains(windowPos))
  790. mShowOverlay = true;
  791. else
  792. mShowOverlay = false;
  793. }
  794. else
  795. mShowOverlay = false;
  796. return true;
  797. }
  798. else if(event.getType() == GUIMouseEventType::MouseDragAndDropDropped)
  799. {
  800. if(DragAndDropManager::instance().getDragTypeId() != (UINT32)DragAndDropType::EditorWidget)
  801. return false;
  802. EditorWidgetBase* draggedWidget = reinterpret_cast<EditorWidgetBase*>(DragAndDropManager::instance().getDragData());
  803. const Vector2I& widgetRelPos = event.getPosition();
  804. const Matrix4& worldTfrm = _getParentWidget()->SO()->getWorldTfrm();
  805. Vector4 tfrmdPos = worldTfrm.multiplyAffine(Vector4((float)widgetRelPos.x, (float)widgetRelPos.y, 0.0f, 1.0f));
  806. Vector2 windowPosVec(tfrmdPos.x, tfrmdPos.y);
  807. Vector2I windowPos(Math::roundToInt(windowPosVec.x), Math::roundToInt(windowPosVec.y));
  808. DockContainer* mouseOverContainer = mRootContainer.findAtPos(windowPos);
  809. if(mouseOverContainer == nullptr)
  810. {
  811. Rect2I overlayBounds = mRootContainer.getContentBounds();
  812. if(overlayBounds.contains(windowPos))
  813. {
  814. insert(nullptr, draggedWidget, DockLocation::None);
  815. }
  816. }
  817. else
  818. {
  819. if(insidePolygon(mTopDropPolygon, 4, windowPosVec))
  820. insert(mouseOverContainer->mWidgets, draggedWidget, DockLocation::Top);
  821. else if(insidePolygon(mBotDropPolygon, 4, windowPosVec))
  822. insert(mouseOverContainer->mWidgets, draggedWidget, DockLocation::Bottom);
  823. else if(insidePolygon(mLeftDropPolygon, 4, windowPosVec))
  824. insert(mouseOverContainer->mWidgets, draggedWidget, DockLocation::Left);
  825. else if(insidePolygon(mRightDropPolygon, 4, windowPosVec))
  826. insert(mouseOverContainer->mWidgets, draggedWidget, DockLocation::Right);
  827. }
  828. return true;
  829. }
  830. return false;
  831. }
  832. // TODO - Move to a separate Polygon class?
  833. bool DockManager::insidePolygon(Vector2* polyPoints, UINT32 numPoints, Vector2 point) const
  834. {
  835. bool isInside = false;
  836. for (UINT32 i = 0, j = numPoints - 1; i < numPoints; j = i++)
  837. {
  838. float lineVal = (polyPoints[j].x - polyPoints[i].x) * (point.y - polyPoints[i].y) / (polyPoints[j].y - polyPoints[i].y) + polyPoints[i].x;
  839. if (((polyPoints[i].y > point.y) != (polyPoints[j].y > point.y)) && (point.x < lineVal))
  840. isInside = !isInside;
  841. }
  842. return isInside;
  843. }
  844. }