BsGUIManager.cpp 53 KB

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