BsGUIManager.cpp 52 KB

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