BsGUIManager.cpp 46 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472
  1. #include "BsGUIManager.h"
  2. #include "BsGUIWidget.h"
  3. #include "BsGUIElement.h"
  4. #include "BsImageSprite.h"
  5. #include "BsSpriteTexture.h"
  6. #include "CmTime.h"
  7. #include "CmSceneObject.h"
  8. #include "CmMaterial.h"
  9. #include "CmMeshData.h"
  10. #include "CmVertexDataDesc.h"
  11. #include "CmMesh.h"
  12. #include "CmUtil.h"
  13. #include "CmRenderWindowManager.h"
  14. #include "CmPlatform.h"
  15. #include "CmRectI.h"
  16. #include "CmApplication.h"
  17. #include "CmException.h"
  18. #include "CmInput.h"
  19. #include "CmPass.h"
  20. #include "CmDebug.h"
  21. #include "CmRenderQueue.h"
  22. #include "BsGUIInputCaret.h"
  23. #include "BsGUIInputSelection.h"
  24. #include "BsGUIListBox.h"
  25. #include "BsGUIButton.h"
  26. #include "BsGUIDropDownBox.h"
  27. #include "BsGUIContextMenu.h"
  28. #include "BsDragAndDropManager.h"
  29. #include "BsGUIDropDownBoxManager.h"
  30. #include "BsGUIContextMenu.h"
  31. #include "CmProfiler.h"
  32. #include "CmMeshHeap.h"
  33. #include "CmTransientMesh.h"
  34. #include "BsVirtualInput.h"
  35. #include "BsCursor.h"
  36. using namespace CamelotFramework;
  37. namespace BansheeEngine
  38. {
  39. struct GUIGroupElement
  40. {
  41. GUIGroupElement()
  42. { }
  43. GUIGroupElement(GUIElement* _element, UINT32 _renderElement)
  44. :element(_element), renderElement(_renderElement)
  45. { }
  46. GUIElement* element;
  47. UINT32 renderElement;
  48. };
  49. struct GUIMaterialGroup
  50. {
  51. GUIMaterialInfo matInfo;
  52. UINT32 numQuads;
  53. UINT32 depth;
  54. RectI bounds;
  55. Vector<GUIGroupElement>::type elements;
  56. };
  57. const UINT32 GUIManager::DRAG_DISTANCE = 3;
  58. const UINT32 GUIManager::MESH_HEAP_INITIAL_NUM_VERTS = 16384;
  59. const UINT32 GUIManager::MESH_HEAP_INITIAL_NUM_INDICES = 49152;
  60. GUIManager::GUIManager()
  61. :mSeparateMeshesByWidget(true), mActiveMouseButton(GUIMouseButton::Left),
  62. mCaretBlinkInterval(0.5f), mCaretLastBlinkTime(0.0f), mCaretColor(1.0f, 0.6588f, 0.0f), mIsCaretOn(false),
  63. mTextSelectionColor(1.0f, 0.6588f, 0.0f), mInputCaret(nullptr), mInputSelection(nullptr), mDragState(DragState::NoDrag),
  64. mActiveCursor(CursorType::Arrow)
  65. {
  66. mOnCursorMovedConn = gInput().onCursorMoved.connect(boost::bind(&GUIManager::onCursorMoved, this, _1));
  67. mOnCursorPressedConn = gInput().onCursorPressed.connect(boost::bind(&GUIManager::onCursorPressed, this, _1));
  68. mOnCursorReleasedConn = gInput().onCursorReleased.connect(boost::bind(&GUIManager::onCursorReleased, this, _1));
  69. mOnCursorDoubleClick = gInput().onDoubleClick.connect(boost::bind(&GUIManager::onCursorDoubleClick, this, _1));
  70. mOnTextInputConn = gInput().onCharInput.connect(boost::bind(&GUIManager::onTextInput, this, _1));
  71. mOnInputCommandConn = gInput().onInputCommand.connect(boost::bind(&GUIManager::onInputCommandEntered, this, _1));
  72. mOnVirtualButtonDown = VirtualInput::instance().onButtonDown.connect(boost::bind(&GUIManager::onVirtualButtonDown, this, _1));
  73. mWindowGainedFocusConn = RenderWindowManager::instance().onFocusGained.connect(boost::bind(&GUIManager::onWindowFocusGained, this, _1));
  74. mWindowLostFocusConn = RenderWindowManager::instance().onFocusLost.connect(boost::bind(&GUIManager::onWindowFocusLost, this, _1));
  75. mMouseLeftWindowConn = Platform::onMouseLeftWindow.connect(boost::bind(&GUIManager::onMouseLeftWindow, this, _1));
  76. mInputCaret = cm_new<GUIInputCaret, PoolAlloc>();
  77. mInputSelection = cm_new<GUIInputSelection, PoolAlloc>();
  78. DragAndDropManager::startUp(cm_new<DragAndDropManager>());
  79. mDragEndedConn = DragAndDropManager::instance().onDragEnded.connect(boost::bind(&GUIManager::onMouseDragEnded, this, _1));
  80. GUIDropDownBoxManager::startUp(cm_new<GUIDropDownBoxManager>());
  81. mVertexDesc = cm_shared_ptr<VertexDataDesc>();
  82. mVertexDesc->addVertElem(VET_FLOAT2, VES_POSITION);
  83. mVertexDesc->addVertElem(VET_FLOAT2, VES_TEXCOORD);
  84. mMeshHeap = MeshHeap::create(MESH_HEAP_INITIAL_NUM_VERTS, MESH_HEAP_INITIAL_NUM_INDICES, mVertexDesc);
  85. // Need to defer this call because I want to make sure all managers are initialized first
  86. deferredCall(std::bind(&GUIManager::updateCaretTexture, this));
  87. deferredCall(std::bind(&GUIManager::updateTextSelectionTexture, this));
  88. }
  89. GUIManager::~GUIManager()
  90. {
  91. GUIDropDownBoxManager::shutDown();
  92. DragAndDropManager::shutDown();
  93. // Make a copy of widgets, since destroying them will remove them from mWidgets and
  94. // we can't iterate over an array thats getting modified
  95. Vector<WidgetInfo>::type widgetCopy = mWidgets;
  96. for(auto& widget : widgetCopy)
  97. widget.widget->destroy();
  98. mOnCursorPressedConn.disconnect();
  99. mOnCursorReleasedConn.disconnect();
  100. mOnCursorMovedConn.disconnect();
  101. mOnCursorDoubleClick.disconnect();
  102. mOnTextInputConn.disconnect();
  103. mOnInputCommandConn.disconnect();
  104. mOnVirtualButtonDown.disconnect();
  105. mDragEndedConn.disconnect();
  106. mWindowGainedFocusConn.disconnect();
  107. mWindowLostFocusConn.disconnect();
  108. mMouseLeftWindowConn.disconnect();
  109. cm_delete<PoolAlloc>(mInputCaret);
  110. cm_delete<PoolAlloc>(mInputSelection);
  111. }
  112. void GUIManager::registerWidget(GUIWidget* widget)
  113. {
  114. mWidgets.push_back(WidgetInfo(widget));
  115. const Viewport* renderTarget = widget->getTarget();
  116. auto findIter = mCachedGUIData.find(renderTarget);
  117. if(findIter == end(mCachedGUIData))
  118. mCachedGUIData[renderTarget] = GUIRenderData();
  119. GUIRenderData& windowData = mCachedGUIData[renderTarget];
  120. windowData.widgets.push_back(widget);
  121. windowData.isDirty = true;
  122. }
  123. void GUIManager::unregisterWidget(GUIWidget* widget)
  124. {
  125. {
  126. auto findIter = std::find_if(begin(mWidgets), end(mWidgets), [=] (const WidgetInfo& x) { return x.widget == widget; } );
  127. if(findIter != mWidgets.end())
  128. mWidgets.erase(findIter);
  129. }
  130. const Viewport* renderTarget = widget->getTarget();
  131. GUIRenderData& renderData = mCachedGUIData[renderTarget];
  132. {
  133. auto findIter = std::find(begin(renderData.widgets), end(renderData.widgets), widget);
  134. if(findIter != end(renderData.widgets))
  135. renderData.widgets.erase(findIter);
  136. }
  137. if(renderData.widgets.size() == 0)
  138. {
  139. mCachedGUIData.erase(renderTarget);
  140. }
  141. else
  142. renderData.isDirty = true;
  143. }
  144. void GUIManager::update()
  145. {
  146. DragAndDropManager::instance().update();
  147. // Update layouts
  148. gProfiler().beginSample("UpdateLayout");
  149. for(auto& widgetInfo : mWidgets)
  150. {
  151. widgetInfo.widget->_updateLayout();
  152. }
  153. gProfiler().endSample("UpdateLayout");
  154. // Blink caret
  155. float curTime = gTime().getTime();
  156. if((curTime - mCaretLastBlinkTime) >= mCaretBlinkInterval)
  157. {
  158. mCaretLastBlinkTime = curTime;
  159. mIsCaretOn = !mIsCaretOn;
  160. mCommandEvent = GUICommandEvent();
  161. mCommandEvent.setType(GUICommandEventType::Redraw);
  162. for(auto& elementInfo : mElementsInFocus)
  163. {
  164. sendCommandEvent(elementInfo.widget, elementInfo.element, mCommandEvent);
  165. }
  166. }
  167. PROFILE_CALL(updateMeshes(), "UpdateMeshes");
  168. mNewElementsUnderCursor.clear();
  169. for(auto& elementInfo : mElementsUnderCursor)
  170. {
  171. if(!elementInfo.element->_isDestroyed())
  172. mNewElementsUnderCursor.push_back(elementInfo);
  173. }
  174. mElementsUnderCursor.swap(mNewElementsUnderCursor);
  175. mNewActiveElements.clear();
  176. for(auto& elementInfo : mActiveElements)
  177. {
  178. if(!elementInfo.element->_isDestroyed())
  179. mNewActiveElements.push_back(elementInfo);
  180. }
  181. mActiveElements.swap(mNewActiveElements);
  182. mNewElementsInFocus.clear();
  183. for(auto& elementInfo : mElementsInFocus)
  184. {
  185. if(!elementInfo.element->_isDestroyed())
  186. mNewElementsInFocus.push_back(elementInfo);
  187. }
  188. mElementsInFocus.swap(mNewElementsInFocus);
  189. for(auto& focusElementInfo : mForcedFocusElements)
  190. {
  191. if(focusElementInfo.element->_isDestroyed())
  192. continue;
  193. if(focusElementInfo.focus)
  194. {
  195. auto iterFind = std::find_if(mElementsInFocus.begin(), mElementsInFocus.end(),
  196. [&](const ElementInfo& x) { return x.element == focusElementInfo.element; });
  197. if(iterFind == mElementsInFocus.end())
  198. {
  199. mElementsInFocus.push_back(ElementInfo(focusElementInfo.element, &focusElementInfo.element->_getParentWidget()));
  200. mCommandEvent = GUICommandEvent();
  201. mCommandEvent.setType(GUICommandEventType::FocusGained);
  202. sendCommandEvent(&focusElementInfo.element->_getParentWidget(), focusElementInfo.element, mCommandEvent);
  203. }
  204. }
  205. else
  206. {
  207. mNewElementsInFocus.clear();
  208. for(auto& elementInfo : mElementsInFocus)
  209. {
  210. if(elementInfo.element == focusElementInfo.element)
  211. {
  212. mCommandEvent = GUICommandEvent();
  213. mCommandEvent.setType(GUICommandEventType::FocusLost);
  214. sendCommandEvent(elementInfo.widget, elementInfo.element, mCommandEvent);
  215. }
  216. else
  217. mNewElementsInFocus.push_back(elementInfo);
  218. }
  219. mElementsInFocus.swap(mNewElementsInFocus);
  220. }
  221. }
  222. mForcedFocusElements.clear();
  223. processDestroyQueue();
  224. }
  225. void GUIManager::render(ViewportPtr& target, CM::RenderQueue& renderQueue) const
  226. {
  227. auto findIter = mCachedGUIData.find(target.get());
  228. if(findIter == mCachedGUIData.end())
  229. return;
  230. const GUIRenderData& renderData = findIter->second;
  231. // Render the meshes
  232. if(mSeparateMeshesByWidget)
  233. {
  234. // TODO - Possible optimization. I currently divide by width/height inside the shader, while it
  235. // might be more optimal to just scale the mesh as the resolution changes?
  236. float invViewportWidth = 1.0f / (target->getWidth() * 0.5f);
  237. float invViewportHeight = 1.0f / (target->getHeight() * 0.5f);
  238. UINT32 meshIdx = 0;
  239. for(auto& mesh : renderData.cachedMeshes)
  240. {
  241. GUIMaterialInfo materialInfo = renderData.cachedMaterials[meshIdx];
  242. GUIWidget* widget = renderData.cachedWidgetsPerMesh[meshIdx];
  243. if(materialInfo.material == nullptr || !materialInfo.material.isLoaded())
  244. {
  245. meshIdx++;
  246. continue;
  247. }
  248. if(mesh == nullptr)
  249. {
  250. meshIdx++;
  251. continue;
  252. }
  253. materialInfo.invViewportWidth.set(invViewportWidth);
  254. materialInfo.invViewportHeight.set(invViewportHeight);
  255. materialInfo.worldTransform.set(widget->SO()->getWorldTfrm());
  256. renderQueue.add(materialInfo.material.getInternalPtr(), mesh, 0, Vector3::ZERO);
  257. meshIdx++;
  258. }
  259. }
  260. else
  261. {
  262. // TODO: I want to avoid separating meshes by widget in the future. On DX11 and GL I can set up a shader
  263. // that accepts multiple world transforms (one for each widget). Then I can add some instance information to vertices
  264. // and render elements using multiple different transforms with a single call.
  265. // Separating meshes can then be used as a compatibility mode for DX9
  266. CM_EXCEPT(NotImplementedException, "Not implemented");
  267. }
  268. }
  269. void GUIManager::updateMeshes()
  270. {
  271. for(auto& cachedMeshData : mCachedGUIData)
  272. {
  273. GUIRenderData& renderData = cachedMeshData.second;
  274. gProfiler().beginSample("UM_A");
  275. // Check if anything is dirty. If nothing is we can skip the update
  276. bool isDirty = renderData.isDirty;
  277. renderData.isDirty = false;
  278. for(auto& widget : renderData.widgets)
  279. {
  280. if(widget->isDirty(true))
  281. {
  282. isDirty = true;
  283. }
  284. }
  285. gProfiler().endSample("UM_A");
  286. if(!isDirty)
  287. continue;
  288. // Make a list of all GUI elements, sorted from farthest to nearest (highest depth to lowest)
  289. auto elemComp = [](const GUIGroupElement& a, const GUIGroupElement& b)
  290. {
  291. UINT32 aDepth = a.element->_getRenderElementDepth(a.renderElement);
  292. UINT32 bDepth = b.element->_getRenderElementDepth(b.renderElement);
  293. // Compare pointers just to differentiate between two elements with the same depth, their order doesn't really matter, but std::set
  294. // requires all elements to be unique
  295. return (aDepth > bDepth) ||
  296. (aDepth == bDepth && a.element > b.element) ||
  297. (aDepth == bDepth && a.element == b.element && a.renderElement > b.renderElement);
  298. };
  299. Set<GUIGroupElement, std::function<bool(const GUIGroupElement&, const GUIGroupElement&)>>::type allElements(elemComp);
  300. for(auto& widget : renderData.widgets)
  301. {
  302. const Vector<GUIElement*>::type& elements = widget->getElements();
  303. for(auto& element : elements)
  304. {
  305. if(element->_isDisabled())
  306. continue;
  307. UINT32 numRenderElems = element->getNumRenderElements();
  308. for(UINT32 i = 0; i < numRenderElems; i++)
  309. {
  310. allElements.insert(GUIGroupElement(element, i));
  311. }
  312. }
  313. }
  314. // Group the elements in such a way so that we end up with a smallest amount of
  315. // meshes, without breaking back to front rendering order
  316. UnorderedMap<UINT64, Vector<GUIMaterialGroup>::type>::type materialGroups;
  317. for(auto& elem : allElements)
  318. {
  319. GUIElement* guiElem = elem.element;
  320. UINT32 renderElemIdx = elem.renderElement;
  321. UINT32 elemDepth = guiElem->_getRenderElementDepth(renderElemIdx);
  322. RectI tfrmedBounds = guiElem->_getClippedBounds();
  323. tfrmedBounds.transform(guiElem->_getParentWidget().SO()->getWorldTfrm());
  324. const GUIMaterialInfo& matInfo = guiElem->getMaterial(renderElemIdx);
  325. UINT64 materialId = matInfo.material->getInternalID(); // TODO - I group based on material ID. So if two widgets used exact copies of the same material
  326. // this system won't detect it. Find a better way of determining material similarity?
  327. // If this is a new material, add a new list of groups
  328. auto findIterMaterial = materialGroups.find(materialId);
  329. if(findIterMaterial == end(materialGroups))
  330. materialGroups[materialId] = Vector<GUIMaterialGroup>::type();
  331. // Try to find a group this material will fit in:
  332. // - Group that has a depth value same or one below elements depth will always be a match
  333. // - Otherwise, we search higher depth values as well, but we only use them if no elements in between those depth values
  334. // overlap the current elements bounds.
  335. Vector<GUIMaterialGroup>::type& allGroups = materialGroups[materialId];
  336. GUIMaterialGroup* foundGroup = nullptr;
  337. for(auto groupIter = allGroups.rbegin(); groupIter != allGroups.rend(); ++groupIter)
  338. {
  339. // If we separate meshes by widget, ignore any groups with widget parents other than mine
  340. if(mSeparateMeshesByWidget)
  341. {
  342. if(groupIter->elements.size() > 0)
  343. {
  344. GUIElement* otherElem = groupIter->elements.begin()->element; // We only need to check the first element
  345. if(&otherElem->_getParentWidget() != &guiElem->_getParentWidget())
  346. continue;
  347. }
  348. }
  349. GUIMaterialGroup& group = *groupIter;
  350. if(group.depth == elemDepth || group.depth == (elemDepth - 1))
  351. {
  352. foundGroup = &group;
  353. break;
  354. }
  355. else
  356. {
  357. UINT32 startDepth = elemDepth;
  358. UINT32 endDepth = group.depth;
  359. RectI potentialGroupBounds = group.bounds;
  360. potentialGroupBounds.encapsulate(tfrmedBounds);
  361. bool foundOverlap = false;
  362. for(auto& material : materialGroups)
  363. {
  364. for(auto& matGroup : material.second)
  365. {
  366. if(&matGroup == &group)
  367. continue;
  368. if(matGroup.depth > startDepth && matGroup.depth < endDepth)
  369. {
  370. if(matGroup.bounds.overlaps(potentialGroupBounds))
  371. {
  372. foundOverlap = true;
  373. break;
  374. }
  375. }
  376. }
  377. }
  378. if(!foundOverlap)
  379. {
  380. foundGroup = &group;
  381. break;
  382. }
  383. }
  384. }
  385. if(foundGroup == nullptr)
  386. {
  387. allGroups.push_back(GUIMaterialGroup());
  388. foundGroup = &allGroups[allGroups.size() - 1];
  389. foundGroup->depth = elemDepth;
  390. foundGroup->bounds = tfrmedBounds;
  391. foundGroup->elements.push_back(GUIGroupElement(guiElem, renderElemIdx));
  392. foundGroup->matInfo = matInfo;
  393. foundGroup->numQuads = guiElem->getNumQuads(renderElemIdx);
  394. }
  395. else
  396. {
  397. foundGroup->bounds.encapsulate(tfrmedBounds);
  398. foundGroup->elements.push_back(GUIGroupElement(guiElem, renderElemIdx));
  399. foundGroup->depth = std::min(foundGroup->depth, elemDepth);
  400. foundGroup->numQuads += guiElem->getNumQuads(renderElemIdx);
  401. }
  402. }
  403. // Make a list of all GUI elements, sorted from farthest to nearest (highest depth to lowest)
  404. auto groupComp = [](GUIMaterialGroup* a, GUIMaterialGroup* b)
  405. {
  406. return (a->depth > b->depth) || (a->depth == b->depth && a > b);
  407. // Compare pointers just to differentiate between two elements with the same depth, their order doesn't really matter, but std::set
  408. // requires all elements to be unique
  409. };
  410. Set<GUIMaterialGroup*, std::function<bool(GUIMaterialGroup*, GUIMaterialGroup*)>>::type sortedGroups(groupComp);
  411. for(auto& material : materialGroups)
  412. {
  413. for(auto& group : material.second)
  414. {
  415. sortedGroups.insert(&group);
  416. }
  417. }
  418. UINT32 numMeshes = (UINT32)sortedGroups.size();
  419. UINT32 oldNumMeshes = (UINT32)renderData.cachedMeshes.size();
  420. if(numMeshes < oldNumMeshes)
  421. {
  422. renderData.cachedMeshes.resize(numMeshes);
  423. }
  424. renderData.cachedMaterials.resize(numMeshes);
  425. if(mSeparateMeshesByWidget)
  426. renderData.cachedWidgetsPerMesh.resize(numMeshes);
  427. // Fill buffers for each group and update their meshes
  428. UINT32 groupIdx = 0;
  429. for(auto& group : sortedGroups)
  430. {
  431. renderData.cachedMaterials[groupIdx] = group->matInfo;
  432. if(mSeparateMeshesByWidget)
  433. {
  434. if(group->elements.size() == 0)
  435. renderData.cachedWidgetsPerMesh[groupIdx] = nullptr;
  436. else
  437. {
  438. GUIElement* elem = group->elements.begin()->element;
  439. renderData.cachedWidgetsPerMesh[groupIdx] = &elem->_getParentWidget();
  440. }
  441. }
  442. MeshDataPtr meshData = cm_shared_ptr<MeshData, PoolAlloc>(group->numQuads * 4, group->numQuads * 6, mVertexDesc);
  443. UINT8* vertices = meshData->getElementData(VES_POSITION);
  444. UINT8* uvs = meshData->getElementData(VES_TEXCOORD);
  445. UINT32* indices = meshData->getIndices32();
  446. UINT32 vertexStride = meshData->getVertexDesc()->getVertexStride();
  447. UINT32 indexStride = meshData->getIndexElementSize();
  448. UINT32 quadOffset = 0;
  449. for(auto& matElement : group->elements)
  450. {
  451. matElement.element->fillBuffer(vertices, uvs, indices, quadOffset, group->numQuads, vertexStride, indexStride, matElement.renderElement);
  452. UINT32 numQuads = matElement.element->getNumQuads(matElement.renderElement);
  453. UINT32 indexStart = quadOffset * 6;
  454. UINT32 indexEnd = indexStart + numQuads * 6;
  455. UINT32 vertOffset = quadOffset * 4;
  456. for(UINT32 i = indexStart; i < indexEnd; i++)
  457. indices[i] += vertOffset;
  458. quadOffset += numQuads;
  459. }
  460. if(groupIdx < (UINT32)renderData.cachedMeshes.size())
  461. {
  462. mMeshHeap->dealloc(renderData.cachedMeshes[groupIdx]);
  463. renderData.cachedMeshes[groupIdx] = mMeshHeap->alloc(meshData);
  464. }
  465. else
  466. {
  467. renderData.cachedMeshes.push_back(mMeshHeap->alloc(meshData));
  468. }
  469. groupIdx++;
  470. }
  471. }
  472. }
  473. void GUIManager::updateCaretTexture()
  474. {
  475. if(mCaretTexture == nullptr)
  476. {
  477. HTexture newTex = Texture::create(TEX_TYPE_2D, 1, 1, 0, PF_R8G8B8A8);
  478. newTex->synchronize(); // TODO - Required due to a bug in allocateSubresourceBuffer
  479. mCaretTexture = SpriteTexture::create(newTex);
  480. }
  481. const HTexture& tex = mCaretTexture->getTexture();
  482. UINT32 subresourceIdx = tex->mapToSubresourceIdx(0, 0);
  483. PixelDataPtr data = tex->allocateSubresourceBuffer(subresourceIdx);
  484. data->setColorAt(mCaretColor, 0, 0);
  485. gCoreAccessor().writeSubresource(tex.getInternalPtr(), tex->mapToSubresourceIdx(0, 0), data);
  486. }
  487. void GUIManager::updateTextSelectionTexture()
  488. {
  489. if(mTextSelectionTexture == nullptr)
  490. {
  491. HTexture newTex = Texture::create(TEX_TYPE_2D, 1, 1, 0, PF_R8G8B8A8);
  492. newTex->synchronize(); // TODO - Required due to a bug in allocateSubresourceBuffer
  493. mTextSelectionTexture = SpriteTexture::create(newTex);
  494. }
  495. const HTexture& tex = mTextSelectionTexture->getTexture();
  496. UINT32 subresourceIdx = tex->mapToSubresourceIdx(0, 0);
  497. PixelDataPtr data = tex->allocateSubresourceBuffer(subresourceIdx);
  498. data->setColorAt(mTextSelectionColor, 0, 0);
  499. gCoreAccessor().writeSubresource(tex.getInternalPtr(), tex->mapToSubresourceIdx(0, 0), data);
  500. }
  501. bool GUIManager::onMouseDragEnded(const CM::PositionalInputEvent& event)
  502. {
  503. GUIMouseButton guiButton = buttonToGUIButton(event.button);
  504. if(DragAndDropManager::instance().isDragInProgress() && guiButton == GUIMouseButton::Left)
  505. {
  506. for(auto& elementInfo : mElementsUnderCursor)
  507. {
  508. Vector2I localPos;
  509. if(elementInfo.widget != nullptr)
  510. localPos = getWidgetRelativePos(*elementInfo.widget, event.screenPos);
  511. bool acceptDrop = true;
  512. if(DragAndDropManager::instance().needsValidDropTarget())
  513. {
  514. acceptDrop = elementInfo.element->_acceptDragAndDrop(localPos, DragAndDropManager::instance().getDragTypeId());
  515. }
  516. if(acceptDrop)
  517. {
  518. mMouseEvent.setDragAndDropDroppedData(localPos, DragAndDropManager::instance().getDragTypeId(), DragAndDropManager::instance().getDragData());
  519. bool processed = sendMouseEvent(elementInfo.widget, elementInfo.element, mMouseEvent);
  520. if(processed)
  521. return true;
  522. }
  523. }
  524. }
  525. return false;
  526. }
  527. void GUIManager::onCursorMoved(const PositionalInputEvent& event)
  528. {
  529. if(event.isUsed())
  530. return;
  531. bool buttonStates[(int)GUIMouseButton::Count];
  532. buttonStates[0] = event.buttonStates[0];
  533. buttonStates[1] = event.buttonStates[1];
  534. buttonStates[2] = event.buttonStates[2];
  535. if(findElementUnderCursor(event.screenPos, buttonStates, event.shift, event.control, event.alt))
  536. event.markAsUsed();
  537. if(mDragState == DragState::HeldWithoutDrag)
  538. {
  539. UINT32 dist = mLastCursorClickPos.manhattanDist(event.screenPos);
  540. if(dist > DRAG_DISTANCE)
  541. {
  542. for(auto& activeElement : mActiveElements)
  543. {
  544. Vector2I localPos = getWidgetRelativePos(*activeElement.widget, event.screenPos);
  545. mMouseEvent.setMouseDragStartData(localPos);
  546. if(sendMouseEvent(activeElement.widget, activeElement.element, mMouseEvent))
  547. event.markAsUsed();
  548. }
  549. mDragState = DragState::Dragging;
  550. }
  551. }
  552. // If mouse is being held down send MouseDrag events
  553. if(mDragState == DragState::Dragging)
  554. {
  555. for(auto& activeElement : mActiveElements)
  556. {
  557. if(mLastCursorScreenPos != event.screenPos)
  558. {
  559. Vector2I localPos = getWidgetRelativePos(*activeElement.widget, event.screenPos);
  560. mMouseEvent.setMouseDragData(localPos, localPos - mLastCursorScreenPos);
  561. if(sendMouseEvent(activeElement.widget, activeElement.element, mMouseEvent))
  562. event.markAsUsed();
  563. }
  564. }
  565. mLastCursorScreenPos = event.screenPos;
  566. // Also if drag is in progress send DragAndDrop events
  567. if(DragAndDropManager::instance().isDragInProgress())
  568. {
  569. bool acceptDrop = true;
  570. for(auto& elementInfo : mElementsUnderCursor)
  571. {
  572. Vector2I localPos = getWidgetRelativePos(*elementInfo.widget, event.screenPos);
  573. acceptDrop = true;
  574. if(DragAndDropManager::instance().needsValidDropTarget())
  575. {
  576. acceptDrop = elementInfo.element->_acceptDragAndDrop(localPos, DragAndDropManager::instance().getDragTypeId());
  577. }
  578. if(acceptDrop)
  579. {
  580. mMouseEvent.setDragAndDropDraggedData(localPos, DragAndDropManager::instance().getDragTypeId(), DragAndDropManager::instance().getDragData());
  581. if(sendMouseEvent(elementInfo.widget, elementInfo.element, mMouseEvent))
  582. {
  583. event.markAsUsed();
  584. break;
  585. }
  586. }
  587. }
  588. if(acceptDrop)
  589. {
  590. if(mActiveCursor != CursorType::ArrowDrag)
  591. {
  592. Cursor::instance().setCursor(CursorType::ArrowDrag);
  593. mActiveCursor = CursorType::ArrowDrag;
  594. }
  595. }
  596. else
  597. {
  598. if(mActiveCursor != CursorType::Deny)
  599. {
  600. Cursor::instance().setCursor(CursorType::Deny);
  601. mActiveCursor = CursorType::Deny;
  602. }
  603. }
  604. }
  605. }
  606. else // Otherwise, send MouseMove events if we are hovering over any element
  607. {
  608. if(mLastCursorScreenPos != event.screenPos)
  609. {
  610. bool moveProcessed = false;
  611. bool hasCustomCursor = false;
  612. for(auto& elementInfo : mElementsUnderCursor)
  613. {
  614. Vector2I localPos = getWidgetRelativePos(*elementInfo.widget, event.screenPos);
  615. if(!moveProcessed)
  616. {
  617. // Send MouseMove event
  618. mMouseEvent.setMouseMoveData(localPos);
  619. moveProcessed = sendMouseEvent(elementInfo.widget, elementInfo.element, mMouseEvent);
  620. if(moveProcessed)
  621. {
  622. event.markAsUsed();
  623. break;
  624. }
  625. }
  626. if(!hasCustomCursor)
  627. {
  628. CursorType newCursor = CursorType::Arrow;
  629. if(elementInfo.element->_hasCustomCursor(localPos, newCursor))
  630. {
  631. if(newCursor != mActiveCursor)
  632. {
  633. Cursor::instance().setCursor(newCursor);
  634. mActiveCursor = newCursor;
  635. }
  636. hasCustomCursor = true;
  637. }
  638. }
  639. if(moveProcessed && hasCustomCursor)
  640. break;
  641. }
  642. if(!hasCustomCursor)
  643. {
  644. if(mActiveCursor != CursorType::Arrow)
  645. {
  646. Cursor::instance().setCursor(CursorType::Arrow);
  647. mActiveCursor = CursorType::Arrow;
  648. }
  649. }
  650. }
  651. mLastCursorScreenPos = event.screenPos;
  652. if(Math::abs(event.mouseWheelScrollAmount) > 0.00001f)
  653. {
  654. for(auto& elementInfo : mElementsUnderCursor)
  655. {
  656. mMouseEvent.setMouseWheelScrollData(event.mouseWheelScrollAmount);
  657. if(sendMouseEvent(elementInfo.widget, elementInfo.element, mMouseEvent))
  658. {
  659. event.markAsUsed();
  660. break;
  661. }
  662. }
  663. }
  664. }
  665. }
  666. void GUIManager::onCursorReleased(const CM::PositionalInputEvent& event)
  667. {
  668. if(event.isUsed())
  669. return;
  670. bool buttonStates[(int)GUIMouseButton::Count];
  671. buttonStates[0] = event.buttonStates[0];
  672. buttonStates[1] = event.buttonStates[1];
  673. buttonStates[2] = event.buttonStates[2];
  674. if(findElementUnderCursor(event.screenPos, buttonStates, event.shift, event.control, event.alt))
  675. event.markAsUsed();
  676. mMouseEvent = GUIMouseEvent(buttonStates, event.shift, event.control, event.alt);
  677. GUIMouseButton guiButton = buttonToGUIButton(event.button);
  678. // Send MouseUp event only if we are over the active element (we don't want to accidentally trigger other elements).
  679. // And only activate when a button that originally caused the active state is released, otherwise ignore it.
  680. if(mActiveMouseButton == guiButton)
  681. {
  682. for(auto& elementInfo : mElementsUnderCursor)
  683. {
  684. auto iterFind2 = std::find_if(mActiveElements.begin(), mActiveElements.end(),
  685. [&](const ElementInfo& x) { return x.element == elementInfo.element; });
  686. if(iterFind2 != mActiveElements.end())
  687. {
  688. Vector2I localPos = getWidgetRelativePos(*elementInfo.widget, event.screenPos);
  689. mMouseEvent.setMouseUpData(localPos, guiButton);
  690. if(sendMouseEvent(elementInfo.widget, elementInfo.element, mMouseEvent))
  691. {
  692. event.markAsUsed();
  693. break;
  694. }
  695. }
  696. }
  697. }
  698. // Send DragEnd event to whichever element is active
  699. bool acceptEndDrag = (mDragState == DragState::Dragging || mDragState == DragState::HeldWithoutDrag) && mActiveMouseButton == guiButton &&
  700. (guiButton == GUIMouseButton::Left);
  701. if(acceptEndDrag)
  702. {
  703. if(mDragState == DragState::Dragging)
  704. {
  705. for(auto& activeElement : mActiveElements)
  706. {
  707. Vector2I localPos = getWidgetRelativePos(*activeElement.widget, event.screenPos);
  708. mMouseEvent.setMouseDragEndData(localPos);
  709. if(sendMouseEvent(activeElement.widget, activeElement.element, mMouseEvent))
  710. event.markAsUsed();
  711. }
  712. }
  713. mDragState = DragState::NoDrag;
  714. }
  715. if(mActiveMouseButton == guiButton)
  716. {
  717. mActiveElements.clear();
  718. mActiveMouseButton = GUIMouseButton::Left;
  719. }
  720. if(mActiveCursor != CursorType::Arrow)
  721. {
  722. Cursor::instance().setCursor(CursorType::Arrow);
  723. mActiveCursor = CursorType::Arrow;
  724. }
  725. }
  726. void GUIManager::onCursorPressed(const CM::PositionalInputEvent& event)
  727. {
  728. if(event.isUsed())
  729. return;
  730. bool buttonStates[(int)GUIMouseButton::Count];
  731. buttonStates[0] = event.buttonStates[0];
  732. buttonStates[1] = event.buttonStates[1];
  733. buttonStates[2] = event.buttonStates[2];
  734. if(findElementUnderCursor(event.screenPos, buttonStates, event.shift, event.control, event.alt))
  735. event.markAsUsed();
  736. mMouseEvent = GUIMouseEvent(buttonStates, event.shift, event.control, event.alt);
  737. GUIMouseButton guiButton = buttonToGUIButton(event.button);
  738. // We only check for mouse down if mouse isn't already being held down, and we are hovering over an element
  739. if(mActiveElements.size() == 0)
  740. {
  741. mNewActiveElements.clear();
  742. for(auto& elementInfo : mElementsUnderCursor)
  743. {
  744. Vector2I localPos = getWidgetRelativePos(*elementInfo.widget, event.screenPos);
  745. mMouseEvent.setMouseDownData(localPos, guiButton);
  746. bool processed = sendMouseEvent(elementInfo.widget, elementInfo.element, mMouseEvent);
  747. if(guiButton == GUIMouseButton::Left)
  748. {
  749. mDragState = DragState::HeldWithoutDrag;
  750. mLastCursorClickPos = event.screenPos;
  751. }
  752. mNewActiveElements.push_back(ElementInfo(elementInfo.element, elementInfo.widget));
  753. mActiveMouseButton = guiButton;
  754. if(processed)
  755. {
  756. event.markAsUsed();
  757. break;
  758. }
  759. }
  760. mActiveElements.swap(mNewActiveElements);
  761. }
  762. mNewElementsInFocus.clear();
  763. mCommandEvent = GUICommandEvent();
  764. // Determine elements that gained focus
  765. mCommandEvent.setType(GUICommandEventType::FocusGained);
  766. for(auto& elementInfo : mElementsUnderCursor)
  767. {
  768. mNewElementsInFocus.push_back(elementInfo);
  769. auto iterFind = std::find_if(begin(mElementsInFocus), end(mElementsInFocus),
  770. [=] (const ElementInfo& x) { return x.element == elementInfo.element; });
  771. if(iterFind == mElementsInFocus.end())
  772. {
  773. sendCommandEvent(elementInfo.widget, elementInfo.element, mCommandEvent);
  774. }
  775. }
  776. // Determine elements that lost focus
  777. mCommandEvent.setType(GUICommandEventType::FocusLost);
  778. for(auto& elementInfo : mElementsInFocus)
  779. {
  780. auto iterFind = std::find_if(begin(mNewElementsInFocus), end(mNewElementsInFocus),
  781. [=] (const ElementInfo& x) { return x.element == elementInfo.element; });
  782. if(iterFind == mNewElementsInFocus.end())
  783. {
  784. sendCommandEvent(elementInfo.widget, elementInfo.element, mCommandEvent);
  785. }
  786. }
  787. if(mElementsUnderCursor.size() > 0)
  788. event.markAsUsed();
  789. mElementsInFocus.swap(mNewElementsInFocus);
  790. // If right click try to open context menu
  791. if(buttonStates[2] == true)
  792. {
  793. for(auto& elementInfo : mElementsUnderCursor)
  794. {
  795. GUIContextMenu* menu = elementInfo.element->getContextMenu();
  796. if(menu != nullptr)
  797. {
  798. const RenderWindow* window = getWidgetWindow(*elementInfo.widget);
  799. Vector2I windowPos = window->screenToWindowPos(event.screenPos);
  800. menu->open(windowPos, *elementInfo.widget);
  801. event.markAsUsed();
  802. break;
  803. }
  804. }
  805. }
  806. }
  807. void GUIManager::onCursorDoubleClick(const CM::PositionalInputEvent& event)
  808. {
  809. if(event.isUsed())
  810. return;
  811. bool buttonStates[(int)GUIMouseButton::Count];
  812. buttonStates[0] = event.buttonStates[0];
  813. buttonStates[1] = event.buttonStates[1];
  814. buttonStates[2] = event.buttonStates[2];
  815. if(findElementUnderCursor(event.screenPos, buttonStates, event.shift, event.control, event.alt))
  816. event.markAsUsed();
  817. mMouseEvent = GUIMouseEvent(buttonStates, event.shift, event.control, event.alt);
  818. GUIMouseButton guiButton = buttonToGUIButton(event.button);
  819. // We only check for mouse down if we are hovering over an element
  820. for(auto& elementInfo : mElementsUnderCursor)
  821. {
  822. Vector2I localPos = getWidgetRelativePos(*elementInfo.widget, event.screenPos);
  823. mMouseEvent.setMouseDoubleClickData(localPos, guiButton);
  824. if(sendMouseEvent(elementInfo.widget, elementInfo.element, mMouseEvent))
  825. {
  826. event.markAsUsed();
  827. break;
  828. }
  829. }
  830. }
  831. void GUIManager::onInputCommandEntered(CM::InputCommandType commandType)
  832. {
  833. if(mElementsInFocus.size() == 0)
  834. return;
  835. mCommandEvent = GUICommandEvent();
  836. switch(commandType)
  837. {
  838. case InputCommandType::Backspace:
  839. mCommandEvent.setType(GUICommandEventType::Backspace);
  840. break;
  841. case InputCommandType::Delete:
  842. mCommandEvent.setType(GUICommandEventType::Delete);
  843. break;
  844. case InputCommandType::Return:
  845. mCommandEvent.setType(GUICommandEventType::Return);
  846. break;
  847. case InputCommandType::Escape:
  848. mCommandEvent.setType(GUICommandEventType::Escape);
  849. break;
  850. case InputCommandType::CursorMoveLeft:
  851. mCommandEvent.setType(GUICommandEventType::MoveLeft);
  852. break;
  853. case InputCommandType::CursorMoveRight:
  854. mCommandEvent.setType(GUICommandEventType::MoveRight);
  855. break;
  856. case InputCommandType::CursorMoveUp:
  857. mCommandEvent.setType(GUICommandEventType::MoveUp);
  858. break;
  859. case InputCommandType::CursorMoveDown:
  860. mCommandEvent.setType(GUICommandEventType::MoveDown);
  861. break;
  862. case InputCommandType::SelectLeft:
  863. mCommandEvent.setType(GUICommandEventType::SelectLeft);
  864. break;
  865. case InputCommandType::SelectRight:
  866. mCommandEvent.setType(GUICommandEventType::SelectRight);
  867. break;
  868. case InputCommandType::SelectUp:
  869. mCommandEvent.setType(GUICommandEventType::SelectUp);
  870. break;
  871. case InputCommandType::SelectDown:
  872. mCommandEvent.setType(GUICommandEventType::SelectDown);
  873. break;
  874. }
  875. for(auto& elementInfo : mElementsInFocus)
  876. {
  877. sendCommandEvent(elementInfo.widget, elementInfo.element, mCommandEvent);
  878. }
  879. }
  880. void GUIManager::onVirtualButtonDown(const VirtualButton& button)
  881. {
  882. mVirtualButtonEvent.setButton(button);
  883. for(auto& elementInFocus : mElementsInFocus)
  884. {
  885. bool processed = sendVirtualButtonEvent(elementInFocus.widget, elementInFocus.element, mVirtualButtonEvent);
  886. if(processed)
  887. break;
  888. }
  889. }
  890. bool GUIManager::findElementUnderCursor(const CM::Vector2I& cursorScreenPos, bool buttonStates[3], bool shift, bool control, bool alt)
  891. {
  892. Vector<const RenderWindow*>::type widgetWindows;
  893. for(auto& widgetInfo : mWidgets)
  894. widgetWindows.push_back(getWidgetWindow(*widgetInfo.widget));
  895. #if CM_DEBUG_MODE
  896. // Checks if all referenced windows actually exist
  897. Vector<RenderWindow*>::type activeWindows = RenderWindowManager::instance().getRenderWindows();
  898. for(auto& window : widgetWindows)
  899. {
  900. if(window == nullptr)
  901. continue;
  902. auto iterFind = std::find(begin(activeWindows), end(activeWindows), window);
  903. if(iterFind == activeWindows.end())
  904. {
  905. CM_EXCEPT(InternalErrorException, "GUI manager has a reference to a window that doesn't exist. \
  906. Please detach all GUIWidgets from windows before destroying a window.");
  907. }
  908. }
  909. #endif
  910. mNewElementsUnderCursor.clear();
  911. const RenderWindow* windowUnderCursor = nullptr;
  912. UnorderedSet<const RenderWindow*>::type uniqueWindows;
  913. for(auto& window : widgetWindows)
  914. {
  915. if(window == nullptr)
  916. continue;
  917. uniqueWindows.insert(window);
  918. }
  919. for(auto& window : uniqueWindows)
  920. {
  921. if(Platform::isPointOverWindow(*window, cursorScreenPos))
  922. {
  923. windowUnderCursor = window;
  924. break;
  925. }
  926. }
  927. if(windowUnderCursor != nullptr)
  928. {
  929. Vector2I windowPos = windowUnderCursor->screenToWindowPos(cursorScreenPos);
  930. Vector4 vecWindowPos((float)windowPos.x, (float)windowPos.y, 0.0f, 1.0f);
  931. UINT32 widgetIdx = 0;
  932. for(auto& widgetInfo : mWidgets)
  933. {
  934. if(widgetWindows[widgetIdx] == nullptr)
  935. {
  936. widgetIdx++;
  937. continue;
  938. }
  939. GUIWidget* widget = widgetInfo.widget;
  940. if(widgetWindows[widgetIdx] == windowUnderCursor && widget->inBounds(windowToBridgedCoords(*widget, windowPos)))
  941. {
  942. const Vector<GUIElement*>::type& elements = widget->getElements();
  943. Vector2I localPos = getWidgetRelativePos(*widget, cursorScreenPos);
  944. // Elements with lowest depth (most to the front) get handled first
  945. for(auto iter = elements.begin(); iter != elements.end(); ++iter)
  946. {
  947. GUIElement* element = *iter;
  948. if(!element->_isDisabled() && element->_isInBounds(localPos))
  949. {
  950. mNewElementsUnderCursor.push_back(ElementInfo(element, widget));
  951. }
  952. }
  953. }
  954. widgetIdx++;
  955. }
  956. }
  957. std::sort(mNewElementsUnderCursor.begin(), mNewElementsUnderCursor.end(),
  958. [](const ElementInfo& a, const ElementInfo& b)
  959. {
  960. return a.element->_getDepth() < b.element->_getDepth();
  961. });
  962. // Send MouseOut and MouseOver events
  963. bool eventProcessed = false;
  964. for(auto& elementInfo : mElementsUnderCursor)
  965. {
  966. GUIElement* element = elementInfo.element;
  967. GUIWidget* widget = elementInfo.widget;
  968. auto iterFind = std::find_if(mNewElementsUnderCursor.begin(), mNewElementsUnderCursor.end(),
  969. [=] (const ElementInfo& x) { return x.element == element; });
  970. if(iterFind == mNewElementsUnderCursor.end())
  971. {
  972. auto iterFind2 = std::find_if(mActiveElements.begin(), mActiveElements.end(),
  973. [=](const ElementInfo& x) { return x.element == element; });
  974. // Send MouseOut event
  975. if(mActiveElements.size() == 0 || iterFind2 != mActiveElements.end())
  976. {
  977. Vector2I curLocalPos = getWidgetRelativePos(*widget, cursorScreenPos);
  978. mMouseEvent.setMouseOutData(curLocalPos);
  979. if(sendMouseEvent(widget, element, mMouseEvent))
  980. eventProcessed = true;
  981. }
  982. }
  983. }
  984. for(auto& elementInfo : mNewElementsUnderCursor)
  985. {
  986. GUIElement* element = elementInfo.element;
  987. GUIWidget* widget = elementInfo.widget;
  988. auto iterFind = std::find_if(begin(mElementsUnderCursor), end(mElementsUnderCursor),
  989. [=] (const ElementInfo& x) { return x.element == element; });
  990. if(iterFind == mElementsUnderCursor.end())
  991. {
  992. auto iterFind2 = std::find_if(mActiveElements.begin(), mActiveElements.end(),
  993. [&](const ElementInfo& x) { return x.element == element; });
  994. // Send MouseOver event
  995. if(mActiveElements.size() == 0 || iterFind2 != mActiveElements.end())
  996. {
  997. Vector2I localPos;
  998. if(widget != nullptr)
  999. localPos = getWidgetRelativePos(*widget, cursorScreenPos);
  1000. mMouseEvent = GUIMouseEvent(buttonStates, shift, control, alt);
  1001. mMouseEvent.setMouseOverData(localPos);
  1002. if(sendMouseEvent(widget, element, mMouseEvent))
  1003. eventProcessed = true;
  1004. }
  1005. }
  1006. }
  1007. mElementsUnderCursor.swap(mNewElementsUnderCursor);
  1008. return eventProcessed;
  1009. }
  1010. void GUIManager::onTextInput(const CM::TextInputEvent& event)
  1011. {
  1012. mTextInputEvent = GUITextInputEvent();
  1013. mTextInputEvent.setData(event.textChar);
  1014. for(auto& elementInFocus : mElementsInFocus)
  1015. {
  1016. if(sendTextInputEvent(elementInFocus.widget, elementInFocus.element, mTextInputEvent))
  1017. event.markAsUsed();
  1018. }
  1019. }
  1020. void GUIManager::onWindowFocusGained(RenderWindow& win)
  1021. {
  1022. for(auto& widgetInfo : mWidgets)
  1023. {
  1024. GUIWidget* widget = widgetInfo.widget;
  1025. if(getWidgetWindow(*widget) == &win)
  1026. widget->ownerWindowFocusChanged();
  1027. }
  1028. }
  1029. void GUIManager::onWindowFocusLost(RenderWindow& win)
  1030. {
  1031. for(auto& widgetInfo : mWidgets)
  1032. {
  1033. GUIWidget* widget = widgetInfo.widget;
  1034. if(getWidgetWindow(*widget) == &win)
  1035. widget->ownerWindowFocusChanged();
  1036. }
  1037. mNewElementsInFocus.clear();
  1038. for(auto& focusedElement : mElementsInFocus)
  1039. {
  1040. if(getWidgetWindow(*focusedElement.widget) == &win)
  1041. {
  1042. mCommandEvent = GUICommandEvent();
  1043. mCommandEvent.setType(GUICommandEventType::FocusLost);
  1044. sendCommandEvent(focusedElement.widget, focusedElement.element, mCommandEvent);
  1045. }
  1046. else
  1047. mNewElementsInFocus.push_back(focusedElement);
  1048. }
  1049. mElementsInFocus.swap(mNewElementsInFocus);
  1050. }
  1051. // We stop getting mouse move events once it leaves the window, so make sure
  1052. // nothing stays in hover state
  1053. void GUIManager::onMouseLeftWindow(CM::RenderWindow* win)
  1054. {
  1055. bool buttonStates[3];
  1056. buttonStates[0] = false;
  1057. buttonStates[1] = false;
  1058. buttonStates[2] = false;
  1059. mNewElementsUnderCursor.clear();
  1060. for(auto& elementInfo : mElementsUnderCursor)
  1061. {
  1062. GUIElement* element = elementInfo.element;
  1063. GUIWidget* widget = elementInfo.widget;
  1064. if(widget->getTarget()->getTarget().get() != win)
  1065. {
  1066. mNewElementsUnderCursor.push_back(elementInfo);
  1067. continue;
  1068. }
  1069. auto iterFind = std::find_if(mActiveElements.begin(), mActiveElements.end(),
  1070. [&](const ElementInfo& x) { return x.element == element; });
  1071. // Send MouseOut event
  1072. if(mActiveElements.size() == 0 || iterFind != mActiveElements.end())
  1073. {
  1074. Vector2I curLocalPos = getWidgetRelativePos(*widget, Vector2I());
  1075. mMouseEvent.setMouseOutData(curLocalPos);
  1076. sendMouseEvent(widget, element, mMouseEvent);
  1077. }
  1078. }
  1079. mElementsUnderCursor.swap(mNewElementsUnderCursor);
  1080. }
  1081. void GUIManager::queueForDestroy(GUIElement* element)
  1082. {
  1083. mScheduledForDestruction.push(element);
  1084. }
  1085. void GUIManager::setFocus(GUIElement* element, bool focus)
  1086. {
  1087. ElementFocusInfo efi;
  1088. efi.element = element;
  1089. efi.focus = focus;
  1090. mForcedFocusElements.push_back(efi);
  1091. }
  1092. void GUIManager::processDestroyQueue()
  1093. {
  1094. // Need two loops and a temporary since element destructors may themselves
  1095. // queue other elements for destruction
  1096. while(!mScheduledForDestruction.empty())
  1097. {
  1098. CM::Stack<GUIElement*>::type toDestroy = mScheduledForDestruction;
  1099. mScheduledForDestruction = CM::Stack<GUIElement*>::type();
  1100. while(!toDestroy.empty())
  1101. {
  1102. cm_delete<PoolAlloc>(toDestroy.top());
  1103. toDestroy.pop();
  1104. }
  1105. }
  1106. }
  1107. void GUIManager::setInputBridge(const CM::RenderTexture* renderTex, const GUIElement* element)
  1108. {
  1109. if(element == nullptr)
  1110. mInputBridge.erase(renderTex);
  1111. else
  1112. mInputBridge[renderTex] = element;
  1113. }
  1114. GUIMouseButton GUIManager::buttonToGUIButton(PositionalInputEventButton cursorButton) const
  1115. {
  1116. if(cursorButton == PositionalInputEventButton::Left)
  1117. return GUIMouseButton::Left;
  1118. else if(cursorButton == PositionalInputEventButton::Middle)
  1119. return GUIMouseButton::Middle;
  1120. else if(cursorButton == PositionalInputEventButton::Right)
  1121. return GUIMouseButton::Right;
  1122. CM_EXCEPT(InvalidParametersException, "Provided button is not a GUI supported mouse button.");
  1123. }
  1124. Vector2I GUIManager::getWidgetRelativePos(const GUIWidget& widget, const Vector2I& screenPos) const
  1125. {
  1126. const RenderWindow* window = getWidgetWindow(widget);
  1127. if(window == nullptr)
  1128. return Vector2I();
  1129. Vector2I windowPos = window->screenToWindowPos(screenPos);
  1130. windowPos = windowToBridgedCoords(widget, windowPos);
  1131. const Matrix4& worldTfrm = widget.SO()->getWorldTfrm();
  1132. Vector4 vecLocalPos = worldTfrm.inverse().multiply3x4(Vector4((float)windowPos.x, (float)windowPos.y, 0.0f, 1.0f));
  1133. Vector2I curLocalPos(Math::roundToInt(vecLocalPos.x), Math::roundToInt(vecLocalPos.y));
  1134. return curLocalPos;
  1135. }
  1136. Vector2I GUIManager::windowToBridgedCoords(const GUIWidget& widget, const Vector2I& windowPos) const
  1137. {
  1138. // This cast might not be valid (the render target could be a window), but we only really need to cast
  1139. // so that mInputBridge map allows us to search through it - we don't access anything unless the target is bridged
  1140. // (in which case we know it is a RenderTexture)
  1141. const RenderTexture* renderTexture = static_cast<const RenderTexture*>(widget.getTarget()->getTarget().get());
  1142. auto iterFind = mInputBridge.find(renderTexture);
  1143. if(iterFind != mInputBridge.end()) // Widget input is bridged, which means we need to transform the coordinates
  1144. {
  1145. const GUIElement* bridgeElement = iterFind->second;
  1146. const Matrix4& worldTfrm = bridgeElement->_getParentWidget().SO()->getWorldTfrm();
  1147. Vector4 vecLocalPos = worldTfrm.inverse().multiply3x4(Vector4((float)windowPos.x, (float)windowPos.y, 0.0f, 1.0f));
  1148. RectI bridgeBounds = bridgeElement->getBounds();
  1149. // Find coordinates relative to the bridge element
  1150. float x = vecLocalPos.x - (float)bridgeBounds.x;
  1151. float y = vecLocalPos.y - (float)bridgeBounds.y;
  1152. float scaleX = renderTexture->getWidth() / (float)bridgeBounds.width;
  1153. float scaleY = renderTexture->getHeight() / (float)bridgeBounds.height;
  1154. return Vector2I(Math::roundToInt(x * scaleX), Math::roundToInt(y * scaleY));
  1155. }
  1156. return windowPos;
  1157. }
  1158. const CM::RenderWindow* GUIManager::getWidgetWindow(const GUIWidget& widget) const
  1159. {
  1160. // This cast might not be valid (the render target could be a window), but we only really need to cast
  1161. // so that mInputBridge map allows us to search through it - we don't access anything unless the target is bridged
  1162. // (in which case we know it is a RenderTexture)
  1163. const RenderTexture* renderTexture = static_cast<const RenderTexture*>(widget.getTarget()->getTarget().get());
  1164. auto iterFind = mInputBridge.find(renderTexture);
  1165. if(iterFind != mInputBridge.end())
  1166. {
  1167. GUIWidget& parentWidget = iterFind->second->_getParentWidget();
  1168. if(&parentWidget != &widget)
  1169. {
  1170. return getWidgetWindow(parentWidget);
  1171. }
  1172. }
  1173. RenderTargetPtr renderTarget = widget.getTarget()->getTarget();
  1174. Vector<RenderWindow*>::type renderWindows = RenderWindowManager::instance().getRenderWindows();
  1175. auto iterFindWin = std::find(renderWindows.begin(), renderWindows.end(), renderTarget.get());
  1176. if(iterFindWin != renderWindows.end())
  1177. return static_cast<RenderWindow*>(renderTarget.get());
  1178. return nullptr;
  1179. }
  1180. bool GUIManager::sendMouseEvent(GUIWidget* widget, GUIElement* element, const GUIMouseEvent& event)
  1181. {
  1182. return widget->_mouseEvent(element, event);
  1183. }
  1184. bool GUIManager::sendTextInputEvent(GUIWidget* widget, GUIElement* element, const GUITextInputEvent& event)
  1185. {
  1186. return widget->_textInputEvent(element, event);
  1187. }
  1188. bool GUIManager::sendCommandEvent(GUIWidget* widget, GUIElement* element, const GUICommandEvent& event)
  1189. {
  1190. return widget->_commandEvent(element, event);
  1191. }
  1192. bool GUIManager::sendVirtualButtonEvent(GUIWidget* widget, GUIElement* element, const GUIVirtualButtonEvent& event)
  1193. {
  1194. return widget->_virtualButtonEvent(element, event);
  1195. }
  1196. GUIManager& gGUIManager()
  1197. {
  1198. return GUIManager::instance();
  1199. }
  1200. }