BsGUIManager.cpp 52 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703
  1. #include "BsGUIManager.h"
  2. #include "BsCGUIWidget.h"
  3. #include "BsGUIElement.h"
  4. #include "BsImageSprite.h"
  5. #include "BsSpriteTexture.h"
  6. #include "BsTime.h"
  7. #include "BsSceneObject.h"
  8. #include "BsMaterial.h"
  9. #include "BsMeshData.h"
  10. #include "BsVertexDataDesc.h"
  11. #include "BsMesh.h"
  12. #include "BsRenderWindowManager.h"
  13. #include "BsPlatform.h"
  14. #include "BsRect2I.h"
  15. #include "BsCoreApplication.h"
  16. #include "BsException.h"
  17. #include "BsInput.h"
  18. #include "BsPass.h"
  19. #include "BsDebug.h"
  20. #include "BsGUIInputCaret.h"
  21. #include "BsGUIInputSelection.h"
  22. #include "BsGUIListBox.h"
  23. #include "BsGUIButton.h"
  24. #include "BsGUIDropDownMenu.h"
  25. #include "BsGUIContextMenu.h"
  26. #include "BsDragAndDropManager.h"
  27. #include "BsGUIDropDownBoxManager.h"
  28. #include "BsGUIContextMenu.h"
  29. #include "BsProfilerCPU.h"
  30. #include "BsMeshHeap.h"
  31. #include "BsTransientMesh.h"
  32. #include "BsVirtualInput.h"
  33. #include "BsCursor.h"
  34. #include "BsCoreThread.h"
  35. #include "BsRendererManager.h"
  36. #include "BsRenderer.h"
  37. #include "BsCamera.h"
  38. using namespace std::placeholders;
  39. namespace BansheeEngine
  40. {
  41. struct GUIGroupElement
  42. {
  43. GUIGroupElement()
  44. { }
  45. GUIGroupElement(GUIElement* _element, UINT32 _renderElement)
  46. :element(_element), renderElement(_renderElement)
  47. { }
  48. GUIElement* element;
  49. UINT32 renderElement;
  50. };
  51. struct GUIMaterialGroup
  52. {
  53. GUIMaterialInfo matInfo;
  54. UINT32 numQuads;
  55. UINT32 depth;
  56. UINT32 minDepth;
  57. Rect2I bounds;
  58. Vector<GUIGroupElement> elements;
  59. };
  60. const UINT32 GUIManager::DRAG_DISTANCE = 3;
  61. const UINT32 GUIManager::MESH_HEAP_INITIAL_NUM_VERTS = 16384;
  62. const UINT32 GUIManager::MESH_HEAP_INITIAL_NUM_INDICES = 49152;
  63. GUIManager::GUIManager()
  64. :mSeparateMeshesByWidget(true), mActiveMouseButton(GUIMouseButton::Left),
  65. mCaretBlinkInterval(0.5f), mCaretLastBlinkTime(0.0f), mCaretColor(1.0f, 0.6588f, 0.0f), mIsCaretOn(false),
  66. mTextSelectionColor(0.0f, 114/255.0f, 188/255.0f), mInputCaret(nullptr), mInputSelection(nullptr),
  67. mDragState(DragState::NoDrag), mActiveCursor(CursorType::Arrow), mCoreDirty(false)
  68. {
  69. mOnPointerMovedConn = gInput().onPointerMoved.connect(std::bind(&GUIManager::onPointerMoved, this, _1));
  70. mOnPointerPressedConn = gInput().onPointerPressed.connect(std::bind(&GUIManager::onPointerPressed, this, _1));
  71. mOnPointerReleasedConn = gInput().onPointerReleased.connect(std::bind(&GUIManager::onPointerReleased, this, _1));
  72. mOnPointerDoubleClick = gInput().onPointerDoubleClick.connect(std::bind(&GUIManager::onPointerDoubleClick, this, _1));
  73. mOnTextInputConn = gInput().onCharInput.connect(std::bind(&GUIManager::onTextInput, this, _1));
  74. mOnInputCommandConn = gInput().onInputCommand.connect(std::bind(&GUIManager::onInputCommandEntered, this, _1));
  75. mOnVirtualButtonDown = VirtualInput::instance().onButtonDown.connect(std::bind(&GUIManager::onVirtualButtonDown, this, _1, _2));
  76. mWindowGainedFocusConn = RenderWindowManager::instance().onFocusGained.connect(std::bind(&GUIManager::onWindowFocusGained, this, _1));
  77. mWindowLostFocusConn = RenderWindowManager::instance().onFocusLost.connect(std::bind(&GUIManager::onWindowFocusLost, this, _1));
  78. mMouseLeftWindowConn = RenderWindowManager::instance().onMouseLeftWindow.connect(std::bind(&GUIManager::onMouseLeftWindow, this, _1));
  79. mInputCaret = bs_new<GUIInputCaret>();
  80. mInputSelection = bs_new<GUIInputSelection>();
  81. DragAndDropManager::startUp();
  82. mDragEndedConn = DragAndDropManager::instance().onDragEnded.connect(std::bind(&GUIManager::onMouseDragEnded, this, _1, _2));
  83. GUIDropDownBoxManager::startUp();
  84. mVertexDesc = bs_shared_ptr_new<VertexDataDesc>();
  85. mVertexDesc->addVertElem(VET_FLOAT2, VES_POSITION);
  86. mVertexDesc->addVertElem(VET_FLOAT2, VES_TEXCOORD);
  87. mMeshHeap = MeshHeap::create(MESH_HEAP_INITIAL_NUM_VERTS, MESH_HEAP_INITIAL_NUM_INDICES, mVertexDesc);
  88. // Need to defer this call because I want to make sure all managers are initialized first
  89. deferredCall(std::bind(&GUIManager::updateCaretTexture, this));
  90. deferredCall(std::bind(&GUIManager::updateTextSelectionTexture, this));
  91. mCore.store(bs_new<GUIManagerCore>(), std::memory_order_release);
  92. }
  93. GUIManager::~GUIManager()
  94. {
  95. GUIDropDownBoxManager::shutDown();
  96. DragAndDropManager::shutDown();
  97. // Make a copy of widgets, since destroying them will remove them from mWidgets and
  98. // we can't iterate over an array thats getting modified
  99. Vector<WidgetInfo> widgetCopy = mWidgets;
  100. for(auto& widget : widgetCopy)
  101. widget.widget->destroy();
  102. // Ensure everything queued get destroyed, loop until queue empties
  103. while (processDestroyQueue())
  104. { }
  105. mOnPointerPressedConn.disconnect();
  106. mOnPointerReleasedConn.disconnect();
  107. mOnPointerMovedConn.disconnect();
  108. mOnPointerDoubleClick.disconnect();
  109. mOnTextInputConn.disconnect();
  110. mOnInputCommandConn.disconnect();
  111. mOnVirtualButtonDown.disconnect();
  112. mDragEndedConn.disconnect();
  113. mWindowGainedFocusConn.disconnect();
  114. mWindowLostFocusConn.disconnect();
  115. mMouseLeftWindowConn.disconnect();
  116. bs_delete(mInputCaret);
  117. bs_delete(mInputSelection);
  118. gCoreAccessor().queueCommand(std::bind(&GUIManager::destroyCore, this, mCore.load(std::memory_order_relaxed)));
  119. assert(mCachedGUIData.size() == 0);
  120. }
  121. void GUIManager::destroyCore(GUIManagerCore* core)
  122. {
  123. bs_delete(core);
  124. }
  125. void GUIManager::registerWidget(CGUIWidget* widget)
  126. {
  127. mWidgets.push_back(WidgetInfo(widget));
  128. const Viewport* renderTarget = widget->getTarget();
  129. auto findIter = mCachedGUIData.find(renderTarget);
  130. if(findIter == end(mCachedGUIData))
  131. mCachedGUIData[renderTarget] = GUIRenderData();
  132. GUIRenderData& windowData = mCachedGUIData[renderTarget];
  133. windowData.widgets.push_back(widget);
  134. windowData.isDirty = true;
  135. }
  136. void GUIManager::unregisterWidget(CGUIWidget* widget)
  137. {
  138. {
  139. auto findIter = std::find_if(begin(mWidgets), end(mWidgets), [=] (const WidgetInfo& x) { return x.widget == widget; } );
  140. if(findIter != mWidgets.end())
  141. mWidgets.erase(findIter);
  142. }
  143. {
  144. auto findIter = std::find_if(begin(mElementsInFocus), end(mElementsInFocus), [=](const ElementInfo& x) { return x.widget == widget; });
  145. if (findIter != mElementsInFocus.end())
  146. findIter->widget = nullptr;
  147. }
  148. {
  149. auto findIter = std::find_if(begin(mElementsUnderPointer), end(mElementsUnderPointer), [=](const ElementInfoUnderPointer& x) { return x.widget == widget; });
  150. if (findIter != mElementsUnderPointer.end())
  151. findIter->widget = nullptr;
  152. }
  153. {
  154. auto findIter = std::find_if(begin(mActiveElements), end(mActiveElements), [=](const ElementInfo& x) { return x.widget == widget; });
  155. if (findIter != mActiveElements.end())
  156. findIter->widget = nullptr;
  157. }
  158. const Viewport* renderTarget = widget->getTarget();
  159. GUIRenderData& renderData = mCachedGUIData[renderTarget];
  160. {
  161. auto findIter = std::find(begin(renderData.widgets), end(renderData.widgets), widget);
  162. if(findIter != end(renderData.widgets))
  163. renderData.widgets.erase(findIter);
  164. }
  165. if(renderData.widgets.size() == 0)
  166. {
  167. for (auto& mesh : renderData.cachedMeshes)
  168. {
  169. if (mesh != nullptr)
  170. mMeshHeap->dealloc(mesh);
  171. }
  172. mCachedGUIData.erase(renderTarget);
  173. mCoreDirty = true;
  174. }
  175. else
  176. renderData.isDirty = true;
  177. }
  178. void GUIManager::update()
  179. {
  180. DragAndDropManager::instance()._update();
  181. // Update layouts
  182. gProfilerCPU().beginSample("UpdateLayout");
  183. for(auto& widgetInfo : mWidgets)
  184. {
  185. widgetInfo.widget->_updateLayout();
  186. }
  187. gProfilerCPU().endSample("UpdateLayout");
  188. // Destroy all queued elements (and loop in case any new ones get queued during destruction)
  189. do
  190. {
  191. mNewElementsUnderPointer.clear();
  192. for (auto& elementInfo : mElementsUnderPointer)
  193. {
  194. if (!elementInfo.element->_isDestroyed())
  195. mNewElementsUnderPointer.push_back(elementInfo);
  196. }
  197. mElementsUnderPointer.swap(mNewElementsUnderPointer);
  198. mNewActiveElements.clear();
  199. for (auto& elementInfo : mActiveElements)
  200. {
  201. if (!elementInfo.element->_isDestroyed())
  202. mNewActiveElements.push_back(elementInfo);
  203. }
  204. mActiveElements.swap(mNewActiveElements);
  205. mNewElementsInFocus.clear();
  206. for (auto& elementInfo : mElementsInFocus)
  207. {
  208. if (!elementInfo.element->_isDestroyed())
  209. mNewElementsInFocus.push_back(elementInfo);
  210. }
  211. mElementsInFocus.swap(mNewElementsInFocus);
  212. for (auto& focusElementInfo : mForcedFocusElements)
  213. {
  214. if (focusElementInfo.element->_isDestroyed())
  215. continue;
  216. if (focusElementInfo.focus)
  217. {
  218. auto iterFind = std::find_if(mElementsInFocus.begin(), mElementsInFocus.end(),
  219. [&](const ElementInfo& x) { return x.element == focusElementInfo.element; });
  220. if (iterFind == mElementsInFocus.end())
  221. {
  222. mElementsInFocus.push_back(ElementInfo(focusElementInfo.element, focusElementInfo.element->_getParentWidget()));
  223. mCommandEvent = GUICommandEvent();
  224. mCommandEvent.setType(GUICommandEventType::FocusGained);
  225. sendCommandEvent(focusElementInfo.element, mCommandEvent);
  226. }
  227. }
  228. else
  229. {
  230. mNewElementsInFocus.clear();
  231. for (auto& elementInfo : mElementsInFocus)
  232. {
  233. if (elementInfo.element == focusElementInfo.element)
  234. {
  235. mCommandEvent = GUICommandEvent();
  236. mCommandEvent.setType(GUICommandEventType::FocusLost);
  237. sendCommandEvent(elementInfo.element, mCommandEvent);
  238. }
  239. else
  240. mNewElementsInFocus.push_back(elementInfo);
  241. }
  242. mElementsInFocus.swap(mNewElementsInFocus);
  243. }
  244. }
  245. mForcedFocusElements.clear();
  246. } while (processDestroyQueue());
  247. // Blink caret
  248. float curTime = gTime().getTime();
  249. if ((curTime - mCaretLastBlinkTime) >= mCaretBlinkInterval)
  250. {
  251. mCaretLastBlinkTime = curTime;
  252. mIsCaretOn = !mIsCaretOn;
  253. mCommandEvent = GUICommandEvent();
  254. mCommandEvent.setType(GUICommandEventType::Redraw);
  255. for (auto& elementInfo : mElementsInFocus)
  256. {
  257. sendCommandEvent(elementInfo.element, mCommandEvent);
  258. }
  259. }
  260. PROFILE_CALL(updateMeshes(), "UpdateMeshes");
  261. // Send potentially updated meshes to core for rendering
  262. if (mCoreDirty)
  263. {
  264. UnorderedMap<SPtr<CameraCore>, Vector<GUICoreRenderData>> corePerCameraData;
  265. for (auto& viewportData : mCachedGUIData)
  266. {
  267. const GUIRenderData& renderData = viewportData.second;
  268. SPtr<Camera> camera;
  269. for (auto& widget : viewportData.second.widgets)
  270. {
  271. camera = widget->getCamera();
  272. if (camera != nullptr)
  273. break;
  274. }
  275. if (camera == nullptr)
  276. continue;
  277. auto insertedData = corePerCameraData.insert(std::make_pair(camera->getCore(), Vector<GUICoreRenderData>()));
  278. Vector<GUICoreRenderData>& cameraData = insertedData.first->second;
  279. UINT32 meshIdx = 0;
  280. for (auto& mesh : renderData.cachedMeshes)
  281. {
  282. GUIMaterialInfo materialInfo = renderData.cachedMaterials[meshIdx];
  283. CGUIWidget* widget = renderData.cachedWidgetsPerMesh[meshIdx];
  284. if (materialInfo.material == nullptr || !materialInfo.material.isLoaded())
  285. {
  286. meshIdx++;
  287. continue;
  288. }
  289. if (mesh == nullptr)
  290. {
  291. meshIdx++;
  292. continue;
  293. }
  294. cameraData.push_back(GUICoreRenderData());
  295. GUICoreRenderData& newEntry = cameraData.back();
  296. newEntry.material = materialInfo.material->getCore();
  297. newEntry.mesh = mesh->getCore();
  298. newEntry.worldTransform = widget->SO()->getWorldTfrm();
  299. meshIdx++;
  300. }
  301. }
  302. GUIManagerCore* core = mCore.load(std::memory_order_relaxed);
  303. gCoreAccessor().queueCommand(std::bind(&GUIManagerCore::updateData, core, corePerCameraData));
  304. mCoreDirty = false;
  305. }
  306. }
  307. void GUIManager::updateMeshes()
  308. {
  309. for(auto& cachedMeshData : mCachedGUIData)
  310. {
  311. GUIRenderData& renderData = cachedMeshData.second;
  312. // Check if anything is dirty. If nothing is we can skip the update
  313. bool isDirty = renderData.isDirty;
  314. renderData.isDirty = false;
  315. for(auto& widget : renderData.widgets)
  316. {
  317. if (widget->isDirty(true))
  318. {
  319. isDirty = true;
  320. }
  321. }
  322. if(!isDirty)
  323. continue;
  324. mCoreDirty = true;
  325. bs_frame_mark();
  326. {
  327. // Make a list of all GUI elements, sorted from farthest to nearest (highest depth to lowest)
  328. auto elemComp = [](const GUIGroupElement& a, const GUIGroupElement& b)
  329. {
  330. UINT32 aDepth = a.element->_getRenderElementDepth(a.renderElement);
  331. UINT32 bDepth = b.element->_getRenderElementDepth(b.renderElement);
  332. // Compare pointers just to differentiate between two elements with the same depth, their order doesn't really matter, but std::set
  333. // requires all elements to be unique
  334. return (aDepth > bDepth) ||
  335. (aDepth == bDepth && a.element > b.element) ||
  336. (aDepth == bDepth && a.element == b.element && a.renderElement > b.renderElement);
  337. };
  338. FrameSet<GUIGroupElement, std::function<bool(const GUIGroupElement&, const GUIGroupElement&)>> allElements(elemComp);
  339. for (auto& widget : renderData.widgets)
  340. {
  341. const Vector<GUIElement*>& elements = widget->getElements();
  342. for (auto& element : elements)
  343. {
  344. if (!element->_isVisible())
  345. continue;
  346. UINT32 numRenderElems = element->_getNumRenderElements();
  347. for (UINT32 i = 0; i < numRenderElems; i++)
  348. {
  349. allElements.insert(GUIGroupElement(element, i));
  350. }
  351. }
  352. }
  353. // Group the elements in such a way so that we end up with a smallest amount of
  354. // meshes, without breaking back to front rendering order
  355. FrameUnorderedMap<UINT64, FrameVector<GUIMaterialGroup>> materialGroups;
  356. for (auto& elem : allElements)
  357. {
  358. GUIElement* guiElem = elem.element;
  359. UINT32 renderElemIdx = elem.renderElement;
  360. UINT32 elemDepth = guiElem->_getRenderElementDepth(renderElemIdx);
  361. Rect2I tfrmedBounds = guiElem->_getClippedBounds();
  362. tfrmedBounds.transform(guiElem->_getParentWidget()->SO()->getWorldTfrm());
  363. const GUIMaterialInfo& matInfo = guiElem->_getMaterial(renderElemIdx);
  364. UINT64 materialId = matInfo.material->getInternalID();
  365. // If this is a new material, add a new list of groups
  366. auto findIterMaterial = materialGroups.find(materialId);
  367. if (findIterMaterial == end(materialGroups))
  368. materialGroups[materialId] = FrameVector<GUIMaterialGroup>();
  369. // Try to find a group this material will fit in:
  370. // - Group that has a depth value same or one below elements depth will always be a match
  371. // - Otherwise, we search higher depth values as well, but we only use them if no elements in between those depth values
  372. // overlap the current elements bounds.
  373. FrameVector<GUIMaterialGroup>& allGroups = materialGroups[materialId];
  374. GUIMaterialGroup* foundGroup = nullptr;
  375. for (auto groupIter = allGroups.rbegin(); groupIter != allGroups.rend(); ++groupIter)
  376. {
  377. // If we separate meshes by widget, ignore any groups with widget parents other than mine
  378. if (mSeparateMeshesByWidget)
  379. {
  380. if (groupIter->elements.size() > 0)
  381. {
  382. GUIElement* otherElem = groupIter->elements.begin()->element; // We only need to check the first element
  383. if (otherElem->_getParentWidget() != guiElem->_getParentWidget())
  384. continue;
  385. }
  386. }
  387. GUIMaterialGroup& group = *groupIter;
  388. if (group.depth == elemDepth)
  389. {
  390. foundGroup = &group;
  391. break;
  392. }
  393. else
  394. {
  395. UINT32 startDepth = elemDepth;
  396. UINT32 endDepth = group.depth;
  397. Rect2I potentialGroupBounds = group.bounds;
  398. potentialGroupBounds.encapsulate(tfrmedBounds);
  399. bool foundOverlap = false;
  400. for (auto& material : materialGroups)
  401. {
  402. for (auto& matGroup : material.second)
  403. {
  404. if (&matGroup == &group)
  405. continue;
  406. if ((matGroup.minDepth >= startDepth && matGroup.minDepth <= endDepth)
  407. || (matGroup.depth >= startDepth && matGroup.depth <= endDepth))
  408. {
  409. if (matGroup.bounds.overlaps(potentialGroupBounds))
  410. {
  411. foundOverlap = true;
  412. break;
  413. }
  414. }
  415. }
  416. }
  417. if (!foundOverlap)
  418. {
  419. foundGroup = &group;
  420. break;
  421. }
  422. }
  423. }
  424. if (foundGroup == nullptr)
  425. {
  426. allGroups.push_back(GUIMaterialGroup());
  427. foundGroup = &allGroups[allGroups.size() - 1];
  428. foundGroup->depth = elemDepth;
  429. foundGroup->minDepth = elemDepth;
  430. foundGroup->bounds = tfrmedBounds;
  431. foundGroup->elements.push_back(GUIGroupElement(guiElem, renderElemIdx));
  432. foundGroup->matInfo = matInfo;
  433. foundGroup->numQuads = guiElem->_getNumQuads(renderElemIdx);
  434. }
  435. else
  436. {
  437. foundGroup->bounds.encapsulate(tfrmedBounds);
  438. foundGroup->elements.push_back(GUIGroupElement(guiElem, renderElemIdx));
  439. foundGroup->minDepth = std::min(foundGroup->minDepth, elemDepth);
  440. foundGroup->numQuads += guiElem->_getNumQuads(renderElemIdx);
  441. }
  442. }
  443. // Make a list of all GUI elements, sorted from farthest to nearest (highest depth to lowest)
  444. auto groupComp = [](GUIMaterialGroup* a, GUIMaterialGroup* b)
  445. {
  446. return (a->depth > b->depth) || (a->depth == b->depth && a > b);
  447. // Compare pointers just to differentiate between two elements with the same depth, their order doesn't really matter, but std::set
  448. // requires all elements to be unique
  449. };
  450. FrameSet<GUIMaterialGroup*, std::function<bool(GUIMaterialGroup*, GUIMaterialGroup*)>> sortedGroups(groupComp);
  451. for(auto& material : materialGroups)
  452. {
  453. for(auto& group : material.second)
  454. {
  455. sortedGroups.insert(&group);
  456. }
  457. }
  458. UINT32 numMeshes = (UINT32)sortedGroups.size();
  459. UINT32 oldNumMeshes = (UINT32)renderData.cachedMeshes.size();
  460. if(numMeshes < oldNumMeshes)
  461. {
  462. for (UINT32 i = numMeshes; i < oldNumMeshes; i++)
  463. mMeshHeap->dealloc(renderData.cachedMeshes[i]);
  464. renderData.cachedMeshes.resize(numMeshes);
  465. }
  466. renderData.cachedMaterials.resize(numMeshes);
  467. if(mSeparateMeshesByWidget)
  468. renderData.cachedWidgetsPerMesh.resize(numMeshes);
  469. // Fill buffers for each group and update their meshes
  470. UINT32 groupIdx = 0;
  471. for(auto& group : sortedGroups)
  472. {
  473. renderData.cachedMaterials[groupIdx] = group->matInfo;
  474. if(mSeparateMeshesByWidget)
  475. {
  476. if(group->elements.size() == 0)
  477. renderData.cachedWidgetsPerMesh[groupIdx] = nullptr;
  478. else
  479. {
  480. GUIElement* elem = group->elements.begin()->element;
  481. renderData.cachedWidgetsPerMesh[groupIdx] = elem->_getParentWidget();
  482. }
  483. }
  484. MeshDataPtr meshData = bs_shared_ptr_new<MeshData>(group->numQuads * 4, group->numQuads * 6, mVertexDesc);
  485. UINT8* vertices = meshData->getElementData(VES_POSITION);
  486. UINT8* uvs = meshData->getElementData(VES_TEXCOORD);
  487. UINT32* indices = meshData->getIndices32();
  488. UINT32 vertexStride = meshData->getVertexDesc()->getVertexStride();
  489. UINT32 indexStride = meshData->getIndexElementSize();
  490. UINT32 quadOffset = 0;
  491. for(auto& matElement : group->elements)
  492. {
  493. matElement.element->_fillBuffer(vertices, uvs, indices, quadOffset, group->numQuads, vertexStride, indexStride, matElement.renderElement);
  494. UINT32 numQuads = matElement.element->_getNumQuads(matElement.renderElement);
  495. UINT32 indexStart = quadOffset * 6;
  496. UINT32 indexEnd = indexStart + numQuads * 6;
  497. UINT32 vertOffset = quadOffset * 4;
  498. for(UINT32 i = indexStart; i < indexEnd; i++)
  499. indices[i] += vertOffset;
  500. quadOffset += numQuads;
  501. }
  502. if(groupIdx < (UINT32)renderData.cachedMeshes.size())
  503. {
  504. mMeshHeap->dealloc(renderData.cachedMeshes[groupIdx]);
  505. renderData.cachedMeshes[groupIdx] = mMeshHeap->alloc(meshData);
  506. }
  507. else
  508. {
  509. renderData.cachedMeshes.push_back(mMeshHeap->alloc(meshData));
  510. }
  511. groupIdx++;
  512. }
  513. }
  514. bs_frame_clear();
  515. }
  516. }
  517. void GUIManager::updateCaretTexture()
  518. {
  519. if(mCaretTexture == nullptr)
  520. {
  521. HTexture newTex = Texture::create(TEX_TYPE_2D, 1, 1, 0, PF_R8G8B8A8);
  522. mCaretTexture = SpriteTexture::create(newTex);
  523. }
  524. const HTexture& tex = mCaretTexture->getTexture();
  525. UINT32 subresourceIdx = tex->getProperties().mapToSubresourceIdx(0, 0);
  526. PixelDataPtr data = tex->getProperties().allocateSubresourceBuffer(subresourceIdx);
  527. data->setColorAt(mCaretColor, 0, 0);
  528. tex->writeSubresource(gCoreAccessor(), subresourceIdx, data, false);
  529. }
  530. void GUIManager::updateTextSelectionTexture()
  531. {
  532. if(mTextSelectionTexture == nullptr)
  533. {
  534. HTexture newTex = Texture::create(TEX_TYPE_2D, 1, 1, 0, PF_R8G8B8A8);
  535. mTextSelectionTexture = SpriteTexture::create(newTex);
  536. }
  537. const HTexture& tex = mTextSelectionTexture->getTexture();
  538. UINT32 subresourceIdx = tex->getProperties().mapToSubresourceIdx(0, 0);
  539. PixelDataPtr data = tex->getProperties().allocateSubresourceBuffer(subresourceIdx);
  540. data->setColorAt(mTextSelectionColor, 0, 0);
  541. tex->writeSubresource(gCoreAccessor(), subresourceIdx, data, false);
  542. }
  543. void GUIManager::onMouseDragEnded(const PointerEvent& event, DragCallbackInfo& dragInfo)
  544. {
  545. GUIMouseButton guiButton = buttonToGUIButton(event.button);
  546. if(DragAndDropManager::instance().isDragInProgress() && guiButton == GUIMouseButton::Left)
  547. {
  548. for(auto& elementInfo : mElementsUnderPointer)
  549. {
  550. Vector2I localPos;
  551. if(elementInfo.widget != nullptr)
  552. localPos = getWidgetRelativePos(elementInfo.widget, event.screenPos);
  553. bool acceptDrop = true;
  554. if(DragAndDropManager::instance().needsValidDropTarget())
  555. {
  556. acceptDrop = elementInfo.element->_acceptDragAndDrop(localPos, DragAndDropManager::instance().getDragTypeId());
  557. }
  558. if(acceptDrop)
  559. {
  560. mMouseEvent.setDragAndDropDroppedData(localPos, DragAndDropManager::instance().getDragTypeId(), DragAndDropManager::instance().getDragData());
  561. dragInfo.processed = sendMouseEvent(elementInfo.element, mMouseEvent);
  562. if(dragInfo.processed)
  563. return;
  564. }
  565. }
  566. }
  567. dragInfo.processed = false;
  568. }
  569. void GUIManager::onPointerMoved(const PointerEvent& event)
  570. {
  571. if(event.isUsed())
  572. return;
  573. bool buttonStates[(int)GUIMouseButton::Count];
  574. buttonStates[0] = event.buttonStates[0];
  575. buttonStates[1] = event.buttonStates[1];
  576. buttonStates[2] = event.buttonStates[2];
  577. if(findElementUnderPointer(event.screenPos, buttonStates, event.shift, event.control, event.alt))
  578. event.markAsUsed();
  579. if(mDragState == DragState::HeldWithoutDrag)
  580. {
  581. UINT32 dist = mLastPointerClickPos.manhattanDist(event.screenPos);
  582. if(dist > DRAG_DISTANCE)
  583. {
  584. for(auto& activeElement : mActiveElements)
  585. {
  586. Vector2I localPos = getWidgetRelativePos(activeElement.widget, event.screenPos);
  587. Vector2I localDragStartPos = getWidgetRelativePos(activeElement.widget, mLastPointerClickPos);
  588. mMouseEvent.setMouseDragStartData(localPos, localDragStartPos);
  589. if(sendMouseEvent(activeElement.element, mMouseEvent))
  590. event.markAsUsed();
  591. }
  592. mDragState = DragState::Dragging;
  593. mDragStartPos = event.screenPos;
  594. }
  595. }
  596. // If mouse is being held down send MouseDrag events
  597. if(mDragState == DragState::Dragging)
  598. {
  599. for(auto& activeElement : mActiveElements)
  600. {
  601. if(mLastPointerScreenPos != event.screenPos)
  602. {
  603. Vector2I localPos = getWidgetRelativePos(activeElement.widget, event.screenPos);
  604. mMouseEvent.setMouseDragData(localPos, event.screenPos - mDragStartPos);
  605. if(sendMouseEvent(activeElement.element, mMouseEvent))
  606. event.markAsUsed();
  607. }
  608. }
  609. mLastPointerScreenPos = event.screenPos;
  610. // Also if drag is in progress send DragAndDrop events
  611. if(DragAndDropManager::instance().isDragInProgress())
  612. {
  613. bool acceptDrop = true;
  614. for(auto& elementInfo : mElementsUnderPointer)
  615. {
  616. Vector2I localPos = getWidgetRelativePos(elementInfo.widget, event.screenPos);
  617. acceptDrop = true;
  618. if(DragAndDropManager::instance().needsValidDropTarget())
  619. {
  620. acceptDrop = elementInfo.element->_acceptDragAndDrop(localPos, DragAndDropManager::instance().getDragTypeId());
  621. }
  622. if(acceptDrop)
  623. {
  624. mMouseEvent.setDragAndDropDraggedData(localPos, DragAndDropManager::instance().getDragTypeId(), DragAndDropManager::instance().getDragData());
  625. if(sendMouseEvent(elementInfo.element, mMouseEvent))
  626. {
  627. event.markAsUsed();
  628. break;
  629. }
  630. }
  631. }
  632. if(acceptDrop)
  633. {
  634. if(mActiveCursor != CursorType::ArrowDrag)
  635. {
  636. Cursor::instance().setCursor(CursorType::ArrowDrag);
  637. mActiveCursor = CursorType::ArrowDrag;
  638. }
  639. }
  640. else
  641. {
  642. if(mActiveCursor != CursorType::Deny)
  643. {
  644. Cursor::instance().setCursor(CursorType::Deny);
  645. mActiveCursor = CursorType::Deny;
  646. }
  647. }
  648. }
  649. }
  650. else // Otherwise, send MouseMove events if we are hovering over any element
  651. {
  652. if(mLastPointerScreenPos != event.screenPos)
  653. {
  654. bool moveProcessed = false;
  655. bool hasCustomCursor = false;
  656. for(auto& elementInfo : mElementsUnderPointer)
  657. {
  658. Vector2I localPos = getWidgetRelativePos(elementInfo.widget, event.screenPos);
  659. if(!moveProcessed)
  660. {
  661. // Send MouseMove event
  662. mMouseEvent.setMouseMoveData(localPos);
  663. moveProcessed = sendMouseEvent(elementInfo.element, mMouseEvent);
  664. if(moveProcessed)
  665. event.markAsUsed();
  666. }
  667. if (mDragState == DragState::NoDrag)
  668. {
  669. CursorType newCursor = CursorType::Arrow;
  670. if(elementInfo.element->_hasCustomCursor(localPos, newCursor))
  671. {
  672. if(newCursor != mActiveCursor)
  673. {
  674. Cursor::instance().setCursor(newCursor);
  675. mActiveCursor = newCursor;
  676. }
  677. hasCustomCursor = true;
  678. }
  679. }
  680. if(moveProcessed)
  681. break;
  682. }
  683. // While dragging we don't want to modify the cursor
  684. if (mDragState == DragState::NoDrag)
  685. {
  686. if (!hasCustomCursor)
  687. {
  688. if (mActiveCursor != CursorType::Arrow)
  689. {
  690. Cursor::instance().setCursor(CursorType::Arrow);
  691. mActiveCursor = CursorType::Arrow;
  692. }
  693. }
  694. }
  695. }
  696. mLastPointerScreenPos = event.screenPos;
  697. if(Math::abs(event.mouseWheelScrollAmount) > 0.00001f)
  698. {
  699. for(auto& elementInfo : mElementsUnderPointer)
  700. {
  701. mMouseEvent.setMouseWheelScrollData(event.mouseWheelScrollAmount);
  702. if(sendMouseEvent(elementInfo.element, mMouseEvent))
  703. {
  704. event.markAsUsed();
  705. break;
  706. }
  707. }
  708. }
  709. }
  710. }
  711. void GUIManager::onPointerReleased(const PointerEvent& event)
  712. {
  713. if(event.isUsed())
  714. return;
  715. bool buttonStates[(int)GUIMouseButton::Count];
  716. buttonStates[0] = event.buttonStates[0];
  717. buttonStates[1] = event.buttonStates[1];
  718. buttonStates[2] = event.buttonStates[2];
  719. if(findElementUnderPointer(event.screenPos, buttonStates, event.shift, event.control, event.alt))
  720. event.markAsUsed();
  721. mMouseEvent = GUIMouseEvent(buttonStates, event.shift, event.control, event.alt);
  722. GUIMouseButton guiButton = buttonToGUIButton(event.button);
  723. // Send MouseUp event only if we are over the active element (we don't want to accidentally trigger other elements).
  724. // And only activate when a button that originally caused the active state is released, otherwise ignore it.
  725. if(mActiveMouseButton == guiButton)
  726. {
  727. for(auto& elementInfo : mElementsUnderPointer)
  728. {
  729. auto iterFind2 = std::find_if(mActiveElements.begin(), mActiveElements.end(),
  730. [&](const ElementInfo& x) { return x.element == elementInfo.element; });
  731. if(iterFind2 != mActiveElements.end())
  732. {
  733. Vector2I localPos = getWidgetRelativePos(elementInfo.widget, event.screenPos);
  734. mMouseEvent.setMouseUpData(localPos, guiButton);
  735. if(sendMouseEvent(elementInfo.element, mMouseEvent))
  736. {
  737. event.markAsUsed();
  738. break;
  739. }
  740. }
  741. }
  742. }
  743. // Send DragEnd event to whichever element is active
  744. bool acceptEndDrag = (mDragState == DragState::Dragging || mDragState == DragState::HeldWithoutDrag) && mActiveMouseButton == guiButton &&
  745. (guiButton == GUIMouseButton::Left);
  746. if(acceptEndDrag)
  747. {
  748. if(mDragState == DragState::Dragging)
  749. {
  750. for(auto& activeElement : mActiveElements)
  751. {
  752. Vector2I localPos = getWidgetRelativePos(activeElement.widget, event.screenPos);
  753. mMouseEvent.setMouseDragEndData(localPos);
  754. if(sendMouseEvent(activeElement.element, mMouseEvent))
  755. event.markAsUsed();
  756. }
  757. }
  758. mDragState = DragState::NoDrag;
  759. }
  760. if(mActiveMouseButton == guiButton)
  761. {
  762. mActiveElements.clear();
  763. mActiveMouseButton = GUIMouseButton::Left;
  764. }
  765. if(mActiveCursor != CursorType::Arrow)
  766. {
  767. Cursor::instance().setCursor(CursorType::Arrow);
  768. mActiveCursor = CursorType::Arrow;
  769. }
  770. }
  771. void GUIManager::onPointerPressed(const PointerEvent& event)
  772. {
  773. if(event.isUsed())
  774. return;
  775. bool buttonStates[(int)GUIMouseButton::Count];
  776. buttonStates[0] = event.buttonStates[0];
  777. buttonStates[1] = event.buttonStates[1];
  778. buttonStates[2] = event.buttonStates[2];
  779. if(findElementUnderPointer(event.screenPos, buttonStates, event.shift, event.control, event.alt))
  780. event.markAsUsed();
  781. mMouseEvent = GUIMouseEvent(buttonStates, event.shift, event.control, event.alt);
  782. GUIMouseButton guiButton = buttonToGUIButton(event.button);
  783. // We only check for mouse down if mouse isn't already being held down, and we are hovering over an element
  784. if(mActiveElements.size() == 0)
  785. {
  786. mNewActiveElements.clear();
  787. for(auto& elementInfo : mElementsUnderPointer)
  788. {
  789. Vector2I localPos = getWidgetRelativePos(elementInfo.widget, event.screenPos);
  790. mMouseEvent.setMouseDownData(localPos, guiButton);
  791. bool processed = sendMouseEvent(elementInfo.element, mMouseEvent);
  792. if(guiButton == GUIMouseButton::Left)
  793. {
  794. mDragState = DragState::HeldWithoutDrag;
  795. mLastPointerClickPos = event.screenPos;
  796. }
  797. mNewActiveElements.push_back(ElementInfo(elementInfo.element, elementInfo.widget));
  798. mActiveMouseButton = guiButton;
  799. if(processed)
  800. {
  801. event.markAsUsed();
  802. break;
  803. }
  804. }
  805. mActiveElements.swap(mNewActiveElements);
  806. }
  807. mNewElementsInFocus.clear();
  808. mCommandEvent = GUICommandEvent();
  809. // Determine elements that gained focus
  810. mCommandEvent.setType(GUICommandEventType::FocusGained);
  811. for(auto& elementInfo : mElementsUnderPointer)
  812. {
  813. mNewElementsInFocus.push_back(ElementInfo(elementInfo.element, elementInfo.widget));
  814. auto iterFind = std::find_if(begin(mElementsInFocus), end(mElementsInFocus),
  815. [=] (const ElementInfo& x) { return x.element == elementInfo.element; });
  816. if(iterFind == mElementsInFocus.end())
  817. {
  818. sendCommandEvent(elementInfo.element, mCommandEvent);
  819. }
  820. }
  821. // Determine elements that lost focus
  822. mCommandEvent.setType(GUICommandEventType::FocusLost);
  823. for(auto& elementInfo : mElementsInFocus)
  824. {
  825. auto iterFind = std::find_if(begin(mNewElementsInFocus), end(mNewElementsInFocus),
  826. [=] (const ElementInfo& x) { return x.element == elementInfo.element; });
  827. if(iterFind == mNewElementsInFocus.end())
  828. {
  829. sendCommandEvent(elementInfo.element, mCommandEvent);
  830. }
  831. }
  832. if(mElementsUnderPointer.size() > 0)
  833. event.markAsUsed();
  834. mElementsInFocus.swap(mNewElementsInFocus);
  835. // If right click try to open context menu
  836. if(buttonStates[2] == true)
  837. {
  838. for(auto& elementInfo : mElementsUnderPointer)
  839. {
  840. GUIContextMenuPtr menu = elementInfo.element->_getContextMenu();
  841. if(menu != nullptr && elementInfo.widget != nullptr)
  842. {
  843. const RenderWindow* window = getWidgetWindow(*elementInfo.widget);
  844. Vector2I windowPos = window->screenToWindowPos(event.screenPos);
  845. menu->open(windowPos, *elementInfo.widget);
  846. event.markAsUsed();
  847. break;
  848. }
  849. }
  850. }
  851. }
  852. void GUIManager::onPointerDoubleClick(const PointerEvent& event)
  853. {
  854. if(event.isUsed())
  855. return;
  856. bool buttonStates[(int)GUIMouseButton::Count];
  857. buttonStates[0] = event.buttonStates[0];
  858. buttonStates[1] = event.buttonStates[1];
  859. buttonStates[2] = event.buttonStates[2];
  860. if(findElementUnderPointer(event.screenPos, buttonStates, event.shift, event.control, event.alt))
  861. event.markAsUsed();
  862. mMouseEvent = GUIMouseEvent(buttonStates, event.shift, event.control, event.alt);
  863. GUIMouseButton guiButton = buttonToGUIButton(event.button);
  864. // We only check for mouse down if we are hovering over an element
  865. for(auto& elementInfo : mElementsUnderPointer)
  866. {
  867. Vector2I localPos = getWidgetRelativePos(elementInfo.widget, event.screenPos);
  868. mMouseEvent.setMouseDoubleClickData(localPos, guiButton);
  869. if(sendMouseEvent(elementInfo.element, mMouseEvent))
  870. {
  871. event.markAsUsed();
  872. break;
  873. }
  874. }
  875. }
  876. void GUIManager::onInputCommandEntered(InputCommandType commandType)
  877. {
  878. if(mElementsInFocus.size() == 0)
  879. return;
  880. mCommandEvent = GUICommandEvent();
  881. switch(commandType)
  882. {
  883. case InputCommandType::Backspace:
  884. mCommandEvent.setType(GUICommandEventType::Backspace);
  885. break;
  886. case InputCommandType::Delete:
  887. mCommandEvent.setType(GUICommandEventType::Delete);
  888. break;
  889. case InputCommandType::Return:
  890. mCommandEvent.setType(GUICommandEventType::Return);
  891. break;
  892. case InputCommandType::Confirm:
  893. mCommandEvent.setType(GUICommandEventType::Confirm);
  894. break;
  895. case InputCommandType::Escape:
  896. mCommandEvent.setType(GUICommandEventType::Escape);
  897. break;
  898. case InputCommandType::CursorMoveLeft:
  899. mCommandEvent.setType(GUICommandEventType::MoveLeft);
  900. break;
  901. case InputCommandType::CursorMoveRight:
  902. mCommandEvent.setType(GUICommandEventType::MoveRight);
  903. break;
  904. case InputCommandType::CursorMoveUp:
  905. mCommandEvent.setType(GUICommandEventType::MoveUp);
  906. break;
  907. case InputCommandType::CursorMoveDown:
  908. mCommandEvent.setType(GUICommandEventType::MoveDown);
  909. break;
  910. case InputCommandType::SelectLeft:
  911. mCommandEvent.setType(GUICommandEventType::SelectLeft);
  912. break;
  913. case InputCommandType::SelectRight:
  914. mCommandEvent.setType(GUICommandEventType::SelectRight);
  915. break;
  916. case InputCommandType::SelectUp:
  917. mCommandEvent.setType(GUICommandEventType::SelectUp);
  918. break;
  919. case InputCommandType::SelectDown:
  920. mCommandEvent.setType(GUICommandEventType::SelectDown);
  921. break;
  922. }
  923. for(auto& elementInfo : mElementsInFocus)
  924. {
  925. sendCommandEvent(elementInfo.element, mCommandEvent);
  926. }
  927. }
  928. void GUIManager::onVirtualButtonDown(const VirtualButton& button, UINT32 deviceIdx)
  929. {
  930. mVirtualButtonEvent.setButton(button);
  931. for(auto& elementInFocus : mElementsInFocus)
  932. {
  933. bool processed = sendVirtualButtonEvent(elementInFocus.element, mVirtualButtonEvent);
  934. if(processed)
  935. break;
  936. }
  937. }
  938. bool GUIManager::findElementUnderPointer(const Vector2I& pointerScreenPos, bool buttonStates[3], bool shift, bool control, bool alt)
  939. {
  940. Vector<const RenderWindow*> widgetWindows;
  941. for(auto& widgetInfo : mWidgets)
  942. widgetWindows.push_back(getWidgetWindow(*widgetInfo.widget));
  943. #if BS_DEBUG_MODE
  944. // Checks if all referenced windows actually exist
  945. Vector<RenderWindow*> activeWindows = RenderWindowManager::instance().getRenderWindows();
  946. for(auto& window : widgetWindows)
  947. {
  948. if(window == nullptr)
  949. continue;
  950. auto iterFind = std::find(begin(activeWindows), end(activeWindows), window);
  951. if(iterFind == activeWindows.end())
  952. {
  953. BS_EXCEPT(InternalErrorException, "GUI manager has a reference to a window that doesn't exist. \
  954. Please detach all GUIWidgets from windows before destroying a window.");
  955. }
  956. }
  957. #endif
  958. mNewElementsUnderPointer.clear();
  959. const RenderWindow* windowUnderPointer = nullptr;
  960. UnorderedSet<const RenderWindow*> uniqueWindows;
  961. for(auto& window : widgetWindows)
  962. {
  963. if(window == nullptr)
  964. continue;
  965. uniqueWindows.insert(window);
  966. }
  967. for(auto& window : uniqueWindows)
  968. {
  969. if(Platform::isPointOverWindow(*window, pointerScreenPos))
  970. {
  971. windowUnderPointer = window;
  972. break;
  973. }
  974. }
  975. if(windowUnderPointer != nullptr)
  976. {
  977. Vector2I windowPos = windowUnderPointer->screenToWindowPos(pointerScreenPos);
  978. Vector4 vecWindowPos((float)windowPos.x, (float)windowPos.y, 0.0f, 1.0f);
  979. UINT32 widgetIdx = 0;
  980. for(auto& widgetInfo : mWidgets)
  981. {
  982. if(widgetWindows[widgetIdx] == nullptr)
  983. {
  984. widgetIdx++;
  985. continue;
  986. }
  987. CGUIWidget* widget = widgetInfo.widget;
  988. if(widgetWindows[widgetIdx] == windowUnderPointer && widget->inBounds(windowToBridgedCoords(*widget, windowPos)))
  989. {
  990. const Vector<GUIElement*>& elements = widget->getElements();
  991. Vector2I localPos = getWidgetRelativePos(widget, pointerScreenPos);
  992. // Elements with lowest depth (most to the front) get handled first
  993. for(auto iter = elements.begin(); iter != elements.end(); ++iter)
  994. {
  995. GUIElement* element = *iter;
  996. if(element->_isVisible() && element->_isInBounds(localPos))
  997. {
  998. ElementInfoUnderPointer elementInfo(element, widget);
  999. auto iterFind = std::find_if(mElementsUnderPointer.begin(), mElementsUnderPointer.end(),
  1000. [=](const ElementInfoUnderPointer& x) { return x.element == element; });
  1001. if (iterFind != mElementsUnderPointer.end())
  1002. {
  1003. elementInfo.usesMouseOver = iterFind->usesMouseOver;
  1004. elementInfo.receivedMouseOver = iterFind->receivedMouseOver;
  1005. }
  1006. mNewElementsUnderPointer.push_back(elementInfo);
  1007. }
  1008. }
  1009. }
  1010. widgetIdx++;
  1011. }
  1012. }
  1013. std::sort(mNewElementsUnderPointer.begin(), mNewElementsUnderPointer.end(),
  1014. [](const ElementInfoUnderPointer& a, const ElementInfoUnderPointer& b)
  1015. {
  1016. return a.element->_getDepth() < b.element->_getDepth();
  1017. });
  1018. // Send MouseOut and MouseOver events
  1019. bool eventProcessed = false;
  1020. for (auto& elementInfo : mNewElementsUnderPointer)
  1021. {
  1022. GUIElement* element = elementInfo.element;
  1023. CGUIWidget* widget = elementInfo.widget;
  1024. if (elementInfo.receivedMouseOver)
  1025. {
  1026. elementInfo.isHovering = true;
  1027. if (elementInfo.usesMouseOver)
  1028. break;
  1029. continue;
  1030. }
  1031. auto iterFind = std::find_if(mActiveElements.begin(), mActiveElements.end(),
  1032. [&](const ElementInfo& x) { return x.element == element; });
  1033. // Send MouseOver event
  1034. if (mActiveElements.size() == 0 || iterFind != mActiveElements.end())
  1035. {
  1036. Vector2I localPos = getWidgetRelativePos(widget, pointerScreenPos);
  1037. mMouseEvent = GUIMouseEvent(buttonStates, shift, control, alt);
  1038. mMouseEvent.setMouseOverData(localPos);
  1039. elementInfo.receivedMouseOver = true;
  1040. elementInfo.isHovering = true;
  1041. if (sendMouseEvent(element, mMouseEvent))
  1042. {
  1043. eventProcessed = true;
  1044. elementInfo.usesMouseOver = true;
  1045. break;
  1046. }
  1047. }
  1048. }
  1049. // Send DragAndDropLeft event - It is similar to MouseOut events but we send it to all
  1050. // elements a user might hover over, while we send mouse over/out events only to active elements while dragging
  1051. if (DragAndDropManager::instance().isDragInProgress())
  1052. {
  1053. for (auto& elementInfo : mElementsUnderPointer)
  1054. {
  1055. auto iterFind = std::find_if(mNewElementsUnderPointer.begin(), mNewElementsUnderPointer.end(),
  1056. [=](const ElementInfoUnderPointer& x) { return x.element == elementInfo.element; });
  1057. if (iterFind == mNewElementsUnderPointer.end())
  1058. {
  1059. Vector2I localPos = getWidgetRelativePos(elementInfo.widget, pointerScreenPos);
  1060. mMouseEvent.setDragAndDropLeftData(localPos, DragAndDropManager::instance().getDragTypeId(), DragAndDropManager::instance().getDragData());
  1061. if (sendMouseEvent(elementInfo.element, mMouseEvent))
  1062. {
  1063. eventProcessed = true;
  1064. break;
  1065. }
  1066. }
  1067. }
  1068. }
  1069. for(auto& elementInfo : mElementsUnderPointer)
  1070. {
  1071. GUIElement* element = elementInfo.element;
  1072. CGUIWidget* widget = elementInfo.widget;
  1073. auto iterFind = std::find_if(mNewElementsUnderPointer.begin(), mNewElementsUnderPointer.end(),
  1074. [=](const ElementInfoUnderPointer& x) { return x.element == element; });
  1075. if (!elementInfo.receivedMouseOver)
  1076. continue;
  1077. if (iterFind == mNewElementsUnderPointer.end() || !iterFind->isHovering)
  1078. {
  1079. auto iterFind2 = std::find_if(mActiveElements.begin(), mActiveElements.end(),
  1080. [=](const ElementInfo& x) { return x.element == element; });
  1081. // Send MouseOut event
  1082. if(mActiveElements.size() == 0 || iterFind2 != mActiveElements.end())
  1083. {
  1084. Vector2I localPos = getWidgetRelativePos(widget, pointerScreenPos);
  1085. mMouseEvent.setMouseOutData(localPos);
  1086. if (sendMouseEvent(element, mMouseEvent))
  1087. {
  1088. eventProcessed = true;
  1089. break;
  1090. }
  1091. }
  1092. }
  1093. }
  1094. mElementsUnderPointer.swap(mNewElementsUnderPointer);
  1095. return eventProcessed;
  1096. }
  1097. void GUIManager::onTextInput(const TextInputEvent& event)
  1098. {
  1099. mTextInputEvent = GUITextInputEvent();
  1100. mTextInputEvent.setData(event.textChar);
  1101. for(auto& elementInFocus : mElementsInFocus)
  1102. {
  1103. if(sendTextInputEvent(elementInFocus.element, mTextInputEvent))
  1104. event.markAsUsed();
  1105. }
  1106. }
  1107. void GUIManager::onWindowFocusGained(RenderWindow& win)
  1108. {
  1109. for(auto& widgetInfo : mWidgets)
  1110. {
  1111. CGUIWidget* widget = widgetInfo.widget;
  1112. if(getWidgetWindow(*widget) == &win)
  1113. widget->ownerWindowFocusChanged();
  1114. }
  1115. }
  1116. void GUIManager::onWindowFocusLost(RenderWindow& win)
  1117. {
  1118. for(auto& widgetInfo : mWidgets)
  1119. {
  1120. CGUIWidget* widget = widgetInfo.widget;
  1121. if(getWidgetWindow(*widget) == &win)
  1122. widget->ownerWindowFocusChanged();
  1123. }
  1124. mNewElementsInFocus.clear();
  1125. for(auto& focusedElement : mElementsInFocus)
  1126. {
  1127. if (focusedElement.element->_isDestroyed())
  1128. continue;
  1129. if (focusedElement.widget != nullptr && getWidgetWindow(*focusedElement.widget) == &win)
  1130. {
  1131. mCommandEvent = GUICommandEvent();
  1132. mCommandEvent.setType(GUICommandEventType::FocusLost);
  1133. sendCommandEvent(focusedElement.element, mCommandEvent);
  1134. }
  1135. else
  1136. mNewElementsInFocus.push_back(focusedElement);
  1137. }
  1138. mElementsInFocus.swap(mNewElementsInFocus);
  1139. }
  1140. // We stop getting mouse move events once it leaves the window, so make sure
  1141. // nothing stays in hover state
  1142. void GUIManager::onMouseLeftWindow(RenderWindow& win)
  1143. {
  1144. bool buttonStates[3];
  1145. buttonStates[0] = false;
  1146. buttonStates[1] = false;
  1147. buttonStates[2] = false;
  1148. mNewElementsUnderPointer.clear();
  1149. for(auto& elementInfo : mElementsUnderPointer)
  1150. {
  1151. GUIElement* element = elementInfo.element;
  1152. CGUIWidget* widget = elementInfo.widget;
  1153. if (widget != nullptr && widget->getTarget()->getTarget().get() != &win)
  1154. {
  1155. mNewElementsUnderPointer.push_back(elementInfo);
  1156. continue;
  1157. }
  1158. auto iterFind = std::find_if(mActiveElements.begin(), mActiveElements.end(),
  1159. [&](const ElementInfo& x) { return x.element == element; });
  1160. // Send MouseOut event
  1161. if(mActiveElements.size() == 0 || iterFind != mActiveElements.end())
  1162. {
  1163. Vector2I localPos = getWidgetRelativePos(widget, Vector2I());
  1164. mMouseEvent.setMouseOutData(localPos);
  1165. sendMouseEvent(element, mMouseEvent);
  1166. }
  1167. }
  1168. mElementsUnderPointer.swap(mNewElementsUnderPointer);
  1169. if(mDragState != DragState::Dragging)
  1170. {
  1171. if(mActiveCursor != CursorType::Arrow)
  1172. {
  1173. Cursor::instance().setCursor(CursorType::Arrow);
  1174. mActiveCursor = CursorType::Arrow;
  1175. }
  1176. }
  1177. }
  1178. void GUIManager::queueForDestroy(GUIElement* element)
  1179. {
  1180. mScheduledForDestruction.push(element);
  1181. }
  1182. void GUIManager::setFocus(GUIElement* element, bool focus)
  1183. {
  1184. ElementFocusInfo efi;
  1185. efi.element = element;
  1186. efi.focus = focus;
  1187. mForcedFocusElements.push_back(efi);
  1188. }
  1189. bool GUIManager::processDestroyQueue()
  1190. {
  1191. Stack<GUIElement*> toDestroy = mScheduledForDestruction;
  1192. mScheduledForDestruction = Stack<GUIElement*>();
  1193. while (!toDestroy.empty())
  1194. {
  1195. bs_delete(toDestroy.top());
  1196. toDestroy.pop();
  1197. }
  1198. return !mScheduledForDestruction.empty();
  1199. }
  1200. void GUIManager::setInputBridge(const RenderTexture* renderTex, const GUIElement* element)
  1201. {
  1202. if(element == nullptr)
  1203. mInputBridge.erase(renderTex);
  1204. else
  1205. mInputBridge[renderTex] = element;
  1206. }
  1207. GUIMouseButton GUIManager::buttonToGUIButton(PointerEventButton pointerButton) const
  1208. {
  1209. if(pointerButton == PointerEventButton::Left)
  1210. return GUIMouseButton::Left;
  1211. else if(pointerButton == PointerEventButton::Middle)
  1212. return GUIMouseButton::Middle;
  1213. else if(pointerButton == PointerEventButton::Right)
  1214. return GUIMouseButton::Right;
  1215. BS_EXCEPT(InvalidParametersException, "Provided button is not a GUI supported mouse button.");
  1216. }
  1217. Vector2I GUIManager::getWidgetRelativePos(const CGUIWidget* widget, const Vector2I& screenPos) const
  1218. {
  1219. if (widget == nullptr)
  1220. return screenPos;
  1221. const RenderWindow* window = getWidgetWindow(*widget);
  1222. if(window == nullptr)
  1223. return Vector2I();
  1224. Vector2I windowPos = window->screenToWindowPos(screenPos);
  1225. windowPos = windowToBridgedCoords(*widget, windowPos);
  1226. const Matrix4& worldTfrm = widget->SO()->getWorldTfrm();
  1227. Vector4 vecLocalPos = worldTfrm.inverse().multiplyAffine(Vector4((float)windowPos.x, (float)windowPos.y, 0.0f, 1.0f));
  1228. Vector2I curLocalPos(Math::roundToInt(vecLocalPos.x), Math::roundToInt(vecLocalPos.y));
  1229. return curLocalPos;
  1230. }
  1231. Vector2I GUIManager::windowToBridgedCoords(const CGUIWidget& widget, const Vector2I& windowPos) const
  1232. {
  1233. // This cast might not be valid (the render target could be a window), but we only really need to cast
  1234. // so that mInputBridge map allows us to search through it - we don't access anything unless the target is bridged
  1235. // (in which case we know it is a RenderTexture)
  1236. const RenderTexture* renderTexture = static_cast<const RenderTexture*>(widget.getTarget()->getTarget().get());
  1237. const RenderTargetProperties& rtProps = renderTexture->getProperties();
  1238. auto iterFind = mInputBridge.find(renderTexture);
  1239. if(iterFind != mInputBridge.end()) // Widget input is bridged, which means we need to transform the coordinates
  1240. {
  1241. const GUIElement* bridgeElement = iterFind->second;
  1242. const Matrix4& worldTfrm = bridgeElement->_getParentWidget()->SO()->getWorldTfrm();
  1243. Vector4 vecLocalPos = worldTfrm.inverse().multiplyAffine(Vector4((float)windowPos.x, (float)windowPos.y, 0.0f, 1.0f));
  1244. Rect2I bridgeBounds = bridgeElement->_getLayoutData().area;
  1245. // Find coordinates relative to the bridge element
  1246. float x = vecLocalPos.x - (float)bridgeBounds.x;
  1247. float y = vecLocalPos.y - (float)bridgeBounds.y;
  1248. float scaleX = rtProps.getWidth() / (float)bridgeBounds.width;
  1249. float scaleY = rtProps.getHeight() / (float)bridgeBounds.height;
  1250. return Vector2I(Math::roundToInt(x * scaleX), Math::roundToInt(y * scaleY));
  1251. }
  1252. return windowPos;
  1253. }
  1254. const RenderWindow* GUIManager::getWidgetWindow(const CGUIWidget& widget) const
  1255. {
  1256. // This cast might not be valid (the render target could be a window), but we only really need to cast
  1257. // so that mInputBridge map allows us to search through it - we don't access anything unless the target is bridged
  1258. // (in which case we know it is a RenderTexture)
  1259. const RenderTexture* renderTexture = static_cast<const RenderTexture*>(widget.getTarget()->getTarget().get());
  1260. auto iterFind = mInputBridge.find(renderTexture);
  1261. if(iterFind != mInputBridge.end())
  1262. {
  1263. CGUIWidget* parentWidget = iterFind->second->_getParentWidget();
  1264. if(parentWidget != &widget)
  1265. {
  1266. return getWidgetWindow(*parentWidget);
  1267. }
  1268. }
  1269. RenderTargetPtr renderTarget = widget.getTarget()->getTarget();
  1270. Vector<RenderWindow*> renderWindows = RenderWindowManager::instance().getRenderWindows();
  1271. auto iterFindWin = std::find(renderWindows.begin(), renderWindows.end(), renderTarget.get());
  1272. if(iterFindWin != renderWindows.end())
  1273. return static_cast<RenderWindow*>(renderTarget.get());
  1274. return nullptr;
  1275. }
  1276. bool GUIManager::sendMouseEvent(GUIElement* element, const GUIMouseEvent& event)
  1277. {
  1278. if (element->_isDestroyed())
  1279. return false;
  1280. return element->_mouseEvent(event);
  1281. }
  1282. bool GUIManager::sendTextInputEvent(GUIElement* element, const GUITextInputEvent& event)
  1283. {
  1284. if (element->_isDestroyed())
  1285. return false;
  1286. return element->_textInputEvent(event);
  1287. }
  1288. bool GUIManager::sendCommandEvent(GUIElement* element, const GUICommandEvent& event)
  1289. {
  1290. if (element->_isDestroyed())
  1291. return false;
  1292. return element->_commandEvent(event);
  1293. }
  1294. bool GUIManager::sendVirtualButtonEvent(GUIElement* element, const GUIVirtualButtonEvent& event)
  1295. {
  1296. if (element->_isDestroyed())
  1297. return false;
  1298. return element->_virtualButtonEvent(event);
  1299. }
  1300. GUIManager& gGUIManager()
  1301. {
  1302. return GUIManager::instance();
  1303. }
  1304. GUIManagerCore::~GUIManagerCore()
  1305. {
  1306. CoreRendererPtr activeRenderer = RendererManager::instance().getActive();
  1307. for (auto& cameraData : mPerCameraData)
  1308. activeRenderer->_unregisterRenderCallback(cameraData.first.get(), -30);
  1309. }
  1310. void GUIManagerCore::updateData(const UnorderedMap<SPtr<CameraCore>, Vector<GUIManager::GUICoreRenderData>>& newPerCameraData)
  1311. {
  1312. bs_frame_mark();
  1313. {
  1314. FrameSet<SPtr<CameraCore>> validCameras;
  1315. CoreRendererPtr activeRenderer = RendererManager::instance().getActive();
  1316. for (auto& newCameraData : newPerCameraData)
  1317. {
  1318. UINT32 idx = 0;
  1319. Vector<RenderData>* renderData = nullptr;
  1320. for (auto& oldCameraData : mPerCameraData)
  1321. {
  1322. if (newCameraData.first == oldCameraData.first)
  1323. {
  1324. renderData = &oldCameraData.second;
  1325. validCameras.insert(oldCameraData.first);
  1326. break;
  1327. }
  1328. idx++;
  1329. }
  1330. if (renderData == nullptr)
  1331. {
  1332. SPtr<CameraCore> camera = newCameraData.first;
  1333. auto insertedData = mPerCameraData.insert(std::make_pair(newCameraData.first, Vector<RenderData>()));
  1334. renderData = &insertedData.first->second;
  1335. activeRenderer->_registerRenderCallback(camera.get(), -30, std::bind(&GUIManagerCore::render, this, camera));
  1336. validCameras.insert(camera);
  1337. }
  1338. renderData->clear();
  1339. for (auto& entry : newCameraData.second)
  1340. {
  1341. renderData->push_back(RenderData());
  1342. RenderData& newEntry = renderData->back();
  1343. newEntry.mesh = entry.mesh;
  1344. newEntry.material = entry.material;
  1345. newEntry.worldTransform = entry.worldTransform;
  1346. newEntry.invViewportWidthParam = newEntry.material->getParamFloat("invViewportWidth");
  1347. newEntry.invViewportHeightParam = newEntry.material->getParamFloat("invViewportHeight");
  1348. newEntry.worldTransformParam = newEntry.material->getParamMat4("worldTransform");
  1349. }
  1350. }
  1351. FrameVector<SPtr<CameraCore>> cameraToRemove;
  1352. for (auto& cameraData : mPerCameraData)
  1353. {
  1354. auto iterFind = validCameras.find(cameraData.first);
  1355. if (iterFind == validCameras.end())
  1356. cameraToRemove.push_back(cameraData.first);
  1357. }
  1358. for (auto& camera : cameraToRemove)
  1359. {
  1360. activeRenderer->_unregisterRenderCallback(camera.get(), -30);
  1361. mPerCameraData.erase(camera);
  1362. }
  1363. }
  1364. bs_frame_clear();
  1365. }
  1366. void GUIManagerCore::render(const SPtr<CameraCore>& camera)
  1367. {
  1368. Vector<RenderData>& renderData = mPerCameraData[camera];
  1369. float invViewportWidth = 1.0f / (camera->getViewport()->getWidth() * 0.5f);
  1370. float invViewportHeight = 1.0f / (camera->getViewport()->getHeight() * 0.5f);
  1371. for (auto& entry : renderData)
  1372. {
  1373. entry.invViewportWidthParam.set(invViewportWidth);
  1374. entry.invViewportHeightParam.set(invViewportHeight);
  1375. entry.worldTransformParam.set(entry.worldTransform);
  1376. // TODO - I shouldn't be re-applying the entire material for each entry, instead just check which programs
  1377. // changed, and apply only those + the modified constant buffers and/or texture.
  1378. CoreRenderer::setPass(entry.material, 0);
  1379. CoreRenderer::draw(entry.mesh, entry.mesh->getProperties().getSubMesh(0));
  1380. }
  1381. }
  1382. }