UiElementComponent.cpp 77 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include "UiElementComponent.h"
  9. #include <AzCore/Math/Crc.h>
  10. #include <AzCore/Serialization/SerializeContext.h>
  11. #include <AzCore/Serialization/EditContext.h>
  12. #include <AzCore/Serialization/DataPatch.h>
  13. #include <AzCore/Serialization/Utils.h>
  14. #include <AzCore/RTTI/BehaviorContext.h>
  15. #include <AzCore/std/sort.h>
  16. #include "UiCanvasComponent.h"
  17. #include <LyShine/IDraw2d.h>
  18. #include <LyShine/Bus/UiTransformBus.h>
  19. #include <LyShine/Bus/UiVisualBus.h>
  20. #include <LyShine/Bus/UiEditorBus.h>
  21. #include <LyShine/Bus/UiRenderBus.h>
  22. #include <LyShine/Bus/UiRenderControlBus.h>
  23. #include <LyShine/Bus/UiInteractionMaskBus.h>
  24. #include <LyShine/Bus/UiInteractableBus.h>
  25. #include <LyShine/Bus/UiEntityContextBus.h>
  26. #include <LyShine/Bus/UiLayoutManagerBus.h>
  27. #include <CryCommon/StlUtils.h>
  28. #include "UiTransform2dComponent.h"
  29. #include "IConsole.h"
  30. ////////////////////////////////////////////////////////////////////////////////////////////////////
  31. // PUBLIC MEMBER FUNCTIONS
  32. ////////////////////////////////////////////////////////////////////////////////////////////////////
  33. ////////////////////////////////////////////////////////////////////////////////////////////////////
  34. UiElementComponent::UiElementComponent()
  35. {
  36. // This is required in order to be able to tell if the element is in the scheduled transform
  37. // recompute list (intrusive_slist doesn't initialize this except in a debug build)
  38. m_next = nullptr;
  39. }
  40. ////////////////////////////////////////////////////////////////////////////////////////////////////
  41. UiElementComponent::~UiElementComponent()
  42. {
  43. // If this element is currently in the list of elements needing a transform recompute then
  44. // remove it from that list since the element is being destroyed
  45. if (m_next)
  46. {
  47. if (m_canvas)
  48. {
  49. m_canvas->UnscheduleElementForTransformRecompute(this);
  50. }
  51. else
  52. {
  53. m_next = nullptr;
  54. }
  55. }
  56. // In normal (correct) usage we have nothing to do here.
  57. // But if a user calls DeleteEntity or just deletes an entity pointer they can delete a UI element
  58. // and leave its parent with a dangling child pointer.
  59. // So we report an error in that case and do some recovery code.
  60. // If we were being deleted via DestroyElement m_parentId would be invalid
  61. if (m_parentId.IsValid())
  62. {
  63. // Note we do not rely on the m_parent pointer because if the canvas is being unloaded for example the
  64. // parent entity could already have been deleted. So we use the parent entity Id to try to find the parent.
  65. AZ::Entity* parent = nullptr;
  66. AZ::ComponentApplicationBus::BroadcastResult(parent, &AZ::ComponentApplicationBus::Events::FindEntity, m_parentId);
  67. // If the parent is found and it is active that suggests something is wrong. When unloading a canvas we
  68. // deactivate all of the UI elements before any are deleted
  69. if (parent && parent->GetState() == AZ::Entity::State::Active)
  70. {
  71. // As a final check see if this element's parent thinks that this is a child, this is almost certain to be the
  72. // case if we got here but, if not, there is nothing more to do
  73. UiElementComponent* parentElementComponent = parent->FindComponent<UiElementComponent>();
  74. if (parentElementComponent)
  75. {
  76. if (parentElementComponent->FindChildByEntityId(GetEntityId()))
  77. {
  78. // This is an error, report the error
  79. AZ_Error("UI", false, "Deleting a UI element entity directly rather than using DestroyElement. Element is named '%s'", m_entity->GetName().c_str());
  80. // Attempt to recover by removing this element from the parent's child list
  81. parentElementComponent->RemoveChild(m_entity);
  82. // And recursively delete any child UI elements (like DestroyElement on this element would have done)
  83. auto childElementComponents = m_childElementComponents;
  84. for (auto child : childElementComponents)
  85. {
  86. // destroy the child
  87. child->DestroyElement();
  88. }
  89. }
  90. }
  91. }
  92. }
  93. }
  94. ////////////////////////////////////////////////////////////////////////////////////////////////////
  95. void UiElementComponent::RenderElement(LyShine::IRenderGraph* renderGraph, bool isInGame)
  96. {
  97. if (!IsFullyInitialized())
  98. {
  99. return;
  100. }
  101. if (!m_isRenderEnabled)
  102. {
  103. return;
  104. }
  105. if (isInGame)
  106. {
  107. if (!m_isEnabled)
  108. {
  109. // Nothing to do - whole element and all children are disabled
  110. return;
  111. }
  112. }
  113. else
  114. {
  115. // We are in editing mode (not running the game)
  116. // Use the UiEditorBus to query any UiEditorComponent on this element to see if this element is
  117. // hidden in the editor
  118. bool isVisible = true;
  119. UiEditorBus::EventResult(isVisible, GetEntityId(), &UiEditorBus::Events::GetIsVisible);
  120. if (!isVisible)
  121. {
  122. return;
  123. }
  124. }
  125. // If a component is connected to the UiRenderControl bus then we give control of rendering this element
  126. // and its children to that component, otherwise follow the standard render path
  127. if (m_renderControlInterface)
  128. {
  129. // give control of rendering this element and its children to the render control component on this element
  130. m_renderControlInterface->Render(renderGraph, this, m_renderInterface, static_cast<int>(m_childElementComponents.size()), isInGame);
  131. }
  132. else
  133. {
  134. // render any component on this element connected to the UiRenderBus
  135. if (m_renderInterface)
  136. {
  137. m_renderInterface->Render(renderGraph);
  138. }
  139. // now render child elements
  140. int numChildren = static_cast<int>(m_childElementComponents.size());
  141. for (int i = 0; i < numChildren; ++i)
  142. {
  143. GetChildElementComponent(i)->RenderElement(renderGraph, isInGame);
  144. }
  145. }
  146. }
  147. ////////////////////////////////////////////////////////////////////////////////////////////////////
  148. LyShine::ElementId UiElementComponent::GetElementId()
  149. {
  150. return m_elementId;
  151. }
  152. ////////////////////////////////////////////////////////////////////////////////////////////////////
  153. LyShine::NameType UiElementComponent::GetName()
  154. {
  155. return GetEntity() ? GetEntity()->GetName() : "";
  156. }
  157. ////////////////////////////////////////////////////////////////////////////////////////////////////
  158. AZ::EntityId UiElementComponent::GetCanvasEntityId()
  159. {
  160. return m_canvas ? m_canvas->GetEntityId() : AZ::EntityId();
  161. }
  162. ////////////////////////////////////////////////////////////////////////////////////////////////////
  163. AZ::Entity* UiElementComponent::GetParent()
  164. {
  165. return m_parent;
  166. }
  167. ////////////////////////////////////////////////////////////////////////////////////////////////////
  168. AZ::EntityId UiElementComponent::GetParentEntityId()
  169. {
  170. return m_parentId;
  171. }
  172. ////////////////////////////////////////////////////////////////////////////////////////////////////
  173. int UiElementComponent::GetNumChildElements()
  174. {
  175. return static_cast<int>(m_childEntityIdOrder.size());
  176. }
  177. ////////////////////////////////////////////////////////////////////////////////////////////////////
  178. AZ::Entity* UiElementComponent::GetChildElement(int index)
  179. {
  180. AZ::Entity* childEntity = nullptr;
  181. if (index >= 0 && index < m_childEntityIdOrder.size())
  182. {
  183. if (AreChildPointersValid())
  184. {
  185. childEntity = GetChildElementComponent(index)->GetEntity();
  186. }
  187. else
  188. {
  189. AZ::ComponentApplicationBus::BroadcastResult(
  190. childEntity, &AZ::ComponentApplicationBus::Events::FindEntity, m_childEntityIdOrder[index].m_entityId);
  191. }
  192. }
  193. return childEntity;
  194. }
  195. ////////////////////////////////////////////////////////////////////////////////////////////////////
  196. AZ::EntityId UiElementComponent::GetChildEntityId(int index)
  197. {
  198. AZ::EntityId childEntityId;
  199. if (index >= 0 && index < m_childEntityIdOrder.size())
  200. {
  201. childEntityId = m_childEntityIdOrder[index].m_entityId;
  202. }
  203. return childEntityId;
  204. }
  205. ////////////////////////////////////////////////////////////////////////////////////////////////////
  206. UiElementInterface* UiElementComponent::GetChildElementInterface(int index)
  207. {
  208. return GetChildElementComponent(index);
  209. }
  210. ////////////////////////////////////////////////////////////////////////////////////////////////////
  211. int UiElementComponent::GetIndexOfChild(const AZ::Entity* child)
  212. {
  213. AZ::EntityId childEntityId = child->GetId();
  214. int numChildren = static_cast<int>(m_childEntityIdOrder.size());
  215. for (int i = 0; i < numChildren; ++i)
  216. {
  217. if (m_childEntityIdOrder[i].m_entityId == childEntityId)
  218. {
  219. return i;
  220. }
  221. }
  222. AZ_Error("UI", false, "The given entity is not a child of this UI element");
  223. return -1;
  224. }
  225. ////////////////////////////////////////////////////////////////////////////////////////////////////
  226. int UiElementComponent::GetIndexOfChildByEntityId(AZ::EntityId childId)
  227. {
  228. int numChildren = static_cast<int>(m_childEntityIdOrder.size());
  229. for (int i = 0; i < numChildren; ++i)
  230. {
  231. if (m_childEntityIdOrder[i].m_entityId == childId)
  232. {
  233. return i;
  234. }
  235. }
  236. AZ_Error("UI", false, "The given entity is not a child of this UI element");
  237. return -1;
  238. }
  239. ////////////////////////////////////////////////////////////////////////////////////////////////////
  240. LyShine::EntityArray UiElementComponent::GetChildElements()
  241. {
  242. int numChildren = static_cast<int>(m_childEntityIdOrder.size());
  243. LyShine::EntityArray children;
  244. children.reserve(numChildren);
  245. // This is one of the rare functions that needs to work before FixupPostLoad has been called because it is called
  246. // from OnSliceInstantiated, so only use m_childElementComponents if it is setup
  247. if (AreChildPointersValid())
  248. {
  249. for (int i = 0; i < numChildren; ++i)
  250. {
  251. children.push_back(GetChildElementComponent(i)->GetEntity());
  252. }
  253. }
  254. else
  255. {
  256. for (auto& childOrderEntry : m_childEntityIdOrder)
  257. {
  258. AZ::Entity* childEntity = nullptr;
  259. AZ::ComponentApplicationBus::BroadcastResult(
  260. childEntity, &AZ::ComponentApplicationBus::Events::FindEntity, childOrderEntry.m_entityId);
  261. if (childEntity)
  262. {
  263. children.push_back(childEntity);
  264. }
  265. }
  266. }
  267. return children;
  268. }
  269. ////////////////////////////////////////////////////////////////////////////////////////////////////
  270. AZStd::vector<AZ::EntityId> UiElementComponent::GetChildEntityIds()
  271. {
  272. AZStd::vector<AZ::EntityId> children;
  273. for (auto& child : m_childEntityIdOrder)
  274. {
  275. children.push_back(child.m_entityId);
  276. }
  277. return children;
  278. }
  279. ////////////////////////////////////////////////////////////////////////////////////////////////////
  280. AZ::Entity* UiElementComponent::CreateChildElement(const LyShine::NameType& name)
  281. {
  282. AzFramework::EntityContextId contextId = AzFramework::EntityContextId::CreateNull();
  283. AzFramework::EntityIdContextQueryBus::EventResult(
  284. contextId, GetEntityId(), &AzFramework::EntityIdContextQueryBus::Events::GetOwningContextId);
  285. AZ::Entity* child = nullptr;
  286. UiEntityContextRequestBus::EventResult(child, contextId, &UiEntityContextRequestBus::Events::CreateUiEntity, name.c_str());
  287. AZ_Assert(child, "Failed to create child entity");
  288. child->Deactivate(); // deactivate so that we can add components
  289. UiElementComponent* elementComponent = child->CreateComponent<UiElementComponent>();
  290. AZ_Assert(elementComponent, "Failed to create UiElementComponent");
  291. elementComponent->m_canvas = m_canvas;
  292. elementComponent->SetParentReferences(m_entity, this);
  293. elementComponent->m_elementId = m_canvas->GenerateId();
  294. child->Activate(); // re-activate
  295. if (AreChildPointersValid()) // must test before m_childEntityIdOrder.push_back
  296. {
  297. m_childElementComponents.push_back(elementComponent);
  298. }
  299. m_childEntityIdOrder.push_back({child->GetId(), m_childEntityIdOrder.size()});
  300. return child;
  301. }
  302. ////////////////////////////////////////////////////////////////////////////////////////////////////
  303. void UiElementComponent::DestroyElement()
  304. {
  305. PrepareElementForDestroy();
  306. DestroyElementEntity(GetEntityId());
  307. }
  308. ////////////////////////////////////////////////////////////////////////////////////////////////////
  309. void UiElementComponent::DestroyElementOnFrameEnd()
  310. {
  311. PrepareElementForDestroy();
  312. if (m_canvas)
  313. {
  314. // Delay deletion of elements to ensure a script canvas can safely destroy its parent
  315. m_canvas->ScheduleElementDestroy(GetEntityId());
  316. }
  317. }
  318. ////////////////////////////////////////////////////////////////////////////////////////////////////
  319. void UiElementComponent::Reparent(AZ::Entity* newParent, AZ::Entity* insertBefore)
  320. {
  321. if (!newParent)
  322. {
  323. if (IsFullyInitialized())
  324. {
  325. newParent = GetCanvasComponent()->GetRootElement();
  326. }
  327. else
  328. {
  329. EmitNotInitializedWarning();
  330. return;
  331. }
  332. }
  333. if (newParent == GetEntity())
  334. {
  335. AZ_Warning("UI", false, "Cannot set an entity's parent to itself")
  336. return;
  337. }
  338. UiElementComponent* newParentElement = newParent->FindComponent<UiElementComponent>();
  339. AZ_Assert(newParentElement, "New parent entity has no UiElementComponent");
  340. // check if the new parent is in a different canvas if so a reparent is not allowed
  341. // and the caller should do a CloneElement and DestroyElement
  342. if (m_canvas != newParentElement->m_canvas)
  343. {
  344. AZ_Warning("UI", false, "Reparent: Cannot reparent an element to a different canvas");
  345. return;
  346. }
  347. if (m_parent)
  348. {
  349. // remove from parent
  350. GetParentElementComponent()->RemoveChild(GetEntity());
  351. }
  352. newParentElement->AddChild(GetEntity(), insertBefore);
  353. SetParentReferences(newParent, newParentElement);
  354. }
  355. ////////////////////////////////////////////////////////////////////////////////////////////////////
  356. void UiElementComponent::ReparentByEntityId(AZ::EntityId newParent, AZ::EntityId insertBefore)
  357. {
  358. AZ::Entity* newParentEntity = nullptr;
  359. if (newParent.IsValid())
  360. {
  361. AZ::ComponentApplicationBus::BroadcastResult(newParentEntity, &AZ::ComponentApplicationBus::Events::FindEntity, newParent);
  362. AZ_Assert(newParentEntity, "Entity for newParent not found");
  363. }
  364. AZ::Entity* insertBeforeEntity = nullptr;
  365. if (insertBefore.IsValid())
  366. {
  367. AZ::ComponentApplicationBus::BroadcastResult(insertBeforeEntity, &AZ::ComponentApplicationBus::Events::FindEntity, insertBefore);
  368. AZ_Assert(insertBeforeEntity, "Entity for insertBefore not found");
  369. }
  370. Reparent(newParentEntity, insertBeforeEntity);
  371. }
  372. ////////////////////////////////////////////////////////////////////////////////////////////////////
  373. void UiElementComponent::AddToParentAtIndex(AZ::Entity* newParent, int index)
  374. {
  375. AZ_Assert(!m_parent, "Element already has a parent");
  376. if (!newParent)
  377. {
  378. if (IsFullyInitialized())
  379. {
  380. newParent = GetCanvasComponent()->GetRootElement();
  381. }
  382. else
  383. {
  384. EmitNotInitializedWarning();
  385. return;
  386. }
  387. }
  388. UiElementComponent* newParentElement = newParent->FindComponent<UiElementComponent>();
  389. AZ_Assert(newParentElement, "New parent entity has no UiElementComponent");
  390. AZ::Entity* insertBefore = nullptr;
  391. if (index >= 0 && index < newParentElement->GetNumChildElements())
  392. {
  393. insertBefore = newParentElement->GetChildElement(index);
  394. }
  395. newParentElement->AddChild(GetEntity(), insertBefore);
  396. SetParentReferences(newParent, newParentElement);
  397. }
  398. ////////////////////////////////////////////////////////////////////////////////////////////////////
  399. void UiElementComponent::RemoveFromParent()
  400. {
  401. if (m_parent)
  402. {
  403. // remove from parent
  404. GetParentElementComponent()->RemoveChild(GetEntity());
  405. SetParentReferences(nullptr, nullptr);
  406. }
  407. }
  408. ////////////////////////////////////////////////////////////////////////////////////////////////////
  409. AZ::Entity* UiElementComponent::FindFrontmostChildContainingPoint(AZ::Vector2 point, bool isInGame)
  410. {
  411. if (!IsFullyInitialized())
  412. {
  413. return nullptr;
  414. }
  415. AZ::Entity* matchElem = nullptr;
  416. // this traverses all of the elements in reverse hierarchy order and returns the first one that
  417. // is containing the point.
  418. // If necessary, this could be optimized using a spatial partitioning data structure.
  419. for (int i = static_cast<int>(m_childEntityIdOrder.size() - 1); !matchElem && i >= 0; i--)
  420. {
  421. AZ::EntityId child = m_childEntityIdOrder[i].m_entityId;
  422. if (!isInGame)
  423. {
  424. // We are in editing mode (not running the game)
  425. // Use the UiEditorBus to query any UiEditorComponent on this element to see if this element is
  426. // hidden in the editor
  427. bool isVisible = true;
  428. UiEditorBus::EventResult(isVisible, child, &UiEditorBus::Events::GetIsVisible);
  429. if (!isVisible)
  430. {
  431. continue;
  432. }
  433. }
  434. UiElementComponent* childElementComponent = GetChildElementComponent(i);
  435. // Check children of this child first
  436. // child elements do not have to be contained in the parent element's bounds
  437. matchElem = childElementComponent->FindFrontmostChildContainingPoint(point, isInGame);
  438. if (!matchElem)
  439. {
  440. bool isSelectable = true;
  441. if (!isInGame)
  442. {
  443. // We are in editing mode (not running the game)
  444. // Use the UiEditorBus to query any UiEditorComponent on this element to see if this element
  445. // can be selected in the editor
  446. UiEditorBus::EventResult(isSelectable, child, &UiEditorBus::Events::GetIsSelectable);
  447. }
  448. if (isSelectable)
  449. {
  450. // if no children of this child matched then check if point is in bounds of this child element
  451. bool isPointInRect = childElementComponent->GetTransform2dComponent()->IsPointInRect(point);
  452. if (isPointInRect)
  453. {
  454. matchElem = childElementComponent->GetEntity();
  455. }
  456. }
  457. }
  458. }
  459. return matchElem;
  460. }
  461. ////////////////////////////////////////////////////////////////////////////////////////////////////
  462. LyShine::EntityArray UiElementComponent::FindAllChildrenIntersectingRect(const AZ::Vector2& bound0, const AZ::Vector2& bound1, bool isInGame)
  463. {
  464. LyShine::EntityArray result;
  465. if (!IsFullyInitialized())
  466. {
  467. return result;
  468. }
  469. // this traverses all of the elements in hierarchy order
  470. for (int i = 0; i < m_childEntityIdOrder.size(); ++i)
  471. {
  472. AZ::EntityId child = m_childEntityIdOrder[i].m_entityId;
  473. if (!isInGame)
  474. {
  475. // We are in editing mode (not running the game)
  476. // Use the UiEditorBus to query any UiEditorComponent on this element to see if this element is
  477. // hidden in the editor
  478. bool isVisible = true;
  479. UiEditorBus::EventResult(isVisible, child, &UiEditorBus::Events::GetIsVisible);
  480. if (!isVisible)
  481. {
  482. continue;
  483. }
  484. }
  485. UiElementComponent* childElementComponent = GetChildElementComponent(i);
  486. // Check children of this child first
  487. // child elements do not have to be contained in the parent element's bounds
  488. LyShine::EntityArray childMatches = childElementComponent->FindAllChildrenIntersectingRect(bound0, bound1, isInGame);
  489. result.insert(result.end(),childMatches.begin(),childMatches.end());
  490. bool isSelectable = true;
  491. if (!isInGame)
  492. {
  493. // We are in editing mode (not running the game)
  494. // Use the UiEditorBus to query any UiEditorComponent on this element to see if this element
  495. // can be selected in the editor
  496. UiEditorBus::EventResult(isSelectable, child, &UiEditorBus::Events::GetIsSelectable);
  497. }
  498. if (isSelectable)
  499. {
  500. // check if point is in bounds of this child element
  501. bool isInRect = childElementComponent->GetTransform2dComponent()->BoundsAreOverlappingRect(bound0, bound1);
  502. if (isInRect)
  503. {
  504. result.push_back(childElementComponent->GetEntity());
  505. }
  506. }
  507. }
  508. return result;
  509. }
  510. ////////////////////////////////////////////////////////////////////////////////////////////////////
  511. AZ::EntityId UiElementComponent::FindInteractableToHandleEvent(AZ::Vector2 point)
  512. {
  513. AZ::EntityId result;
  514. if (!IsFullyInitialized() || !m_isEnabled)
  515. {
  516. // Nothing to do
  517. return result;
  518. }
  519. // first check the children (in reverse order) since children are in front of parent
  520. {
  521. // if this element is masking children at this point then don't check the children
  522. bool isMasked = false;
  523. UiInteractionMaskBus::EventResult(isMasked, GetEntityId(), &UiInteractionMaskBus::Events::IsPointMasked, point);
  524. if (!isMasked)
  525. {
  526. for (int i = static_cast<int>(m_childEntityIdOrder.size() - 1); !result.IsValid() && i >= 0; i--)
  527. {
  528. result = GetChildElementComponent(i)->FindInteractableToHandleEvent(point);
  529. }
  530. }
  531. }
  532. // if no match then check this element
  533. if (!result.IsValid())
  534. {
  535. // if this element has an interactable component and the point is in this element's rect
  536. if (UiInteractableBus::FindFirstHandler(GetEntityId()))
  537. {
  538. bool isInRect = GetTransform2dComponent()->IsPointInRect(point);
  539. if (isInRect)
  540. {
  541. // check if this interactable component is in a state where it can handle an event at the given point
  542. bool canHandle = false;
  543. UiInteractableBus::EventResult(canHandle, GetEntityId(), &UiInteractableBus::Events::CanHandleEvent, point);
  544. if (canHandle)
  545. {
  546. result = GetEntityId();
  547. }
  548. }
  549. }
  550. }
  551. return result;
  552. }
  553. ////////////////////////////////////////////////////////////////////////////////////////////////////
  554. AZ::EntityId UiElementComponent::FindParentInteractableSupportingDrag(AZ::Vector2 point)
  555. {
  556. AZ::EntityId result;
  557. // if this element has a parent and this element is not completely disabled
  558. if (m_parent && m_isEnabled)
  559. {
  560. AZ::EntityId parentEntity = m_parent->GetId();
  561. // if the parent supports drag hand off then return it
  562. bool supportsDragOffset = false;
  563. UiInteractableBus::EventResult(supportsDragOffset, parentEntity, &UiInteractableBus::Events::DoesSupportDragHandOff, point);
  564. if (supportsDragOffset)
  565. {
  566. // Make sure the parent is also handling events
  567. bool handlingEvents = false;
  568. UiInteractableBus::EventResult(handlingEvents, parentEntity, &UiInteractableBus::Events::IsHandlingEvents);
  569. supportsDragOffset = handlingEvents;
  570. }
  571. if (supportsDragOffset)
  572. {
  573. result = parentEntity;
  574. }
  575. else
  576. {
  577. // else keep going up the parent links
  578. result = GetParentElementComponent()->FindParentInteractableSupportingDrag(point);
  579. }
  580. }
  581. return result;
  582. }
  583. ////////////////////////////////////////////////////////////////////////////////////////////////////
  584. AZ::Entity* UiElementComponent::FindChildByName(const LyShine::NameType& name)
  585. {
  586. AZ::Entity* matchElem = nullptr;
  587. if (AreChildPointersValid())
  588. {
  589. int numChildren = static_cast<int>(m_childElementComponents.size());
  590. for (int i = 0; i < numChildren; ++i)
  591. {
  592. AZ::Entity* childEntity = GetChildElementComponent(i)->GetEntity();
  593. if (name == childEntity->GetName())
  594. {
  595. matchElem = childEntity;
  596. break;
  597. }
  598. }
  599. }
  600. else
  601. {
  602. for (auto& child : m_childEntityIdOrder)
  603. {
  604. AZ::Entity* childEntity = nullptr;
  605. AZ::ComponentApplicationBus::BroadcastResult(childEntity, &AZ::ComponentApplicationBus::Events::FindEntity, child.m_entityId);
  606. if (childEntity && name == childEntity->GetName())
  607. {
  608. matchElem = childEntity;
  609. break;
  610. }
  611. }
  612. }
  613. return matchElem;
  614. }
  615. ////////////////////////////////////////////////////////////////////////////////////////////////////
  616. AZ::Entity* UiElementComponent::FindDescendantByName(const LyShine::NameType& name)
  617. {
  618. AZ::Entity* matchElem = nullptr;
  619. if (AreChildPointersValid())
  620. {
  621. int numChildren = static_cast<int>(m_childElementComponents.size());
  622. for (int i = 0; i < numChildren; ++i)
  623. {
  624. UiElementComponent* childElementComponent = GetChildElementComponent(i);
  625. AZ::Entity* childEntity = childElementComponent->GetEntity();
  626. if (name == childEntity->GetName())
  627. {
  628. matchElem = childEntity;
  629. break;
  630. }
  631. matchElem = childElementComponent->FindDescendantByName(name);
  632. if (matchElem)
  633. {
  634. break;
  635. }
  636. }
  637. }
  638. else
  639. {
  640. for (auto& child : m_childEntityIdOrder)
  641. {
  642. AZ::Entity* childEntity = nullptr;
  643. AZ::ComponentApplicationBus::BroadcastResult(childEntity, &AZ::ComponentApplicationBus::Events::FindEntity, child.m_entityId);
  644. if (childEntity && name == childEntity->GetName())
  645. {
  646. matchElem = childEntity;
  647. break;
  648. }
  649. UiElementBus::EventResult(matchElem, child.m_entityId, &UiElementBus::Events::FindDescendantByName, name);
  650. if (matchElem)
  651. {
  652. break;
  653. }
  654. }
  655. }
  656. return matchElem;
  657. }
  658. ////////////////////////////////////////////////////////////////////////////////////////////////////
  659. AZ::EntityId UiElementComponent::FindChildEntityIdByName(const LyShine::NameType& name)
  660. {
  661. AZ::Entity* childEntity = FindChildByName(name);
  662. return childEntity ? childEntity->GetId() : AZ::EntityId();
  663. }
  664. ////////////////////////////////////////////////////////////////////////////////////////////////////
  665. AZ::EntityId UiElementComponent::FindDescendantEntityIdByName(const LyShine::NameType& name)
  666. {
  667. AZ::Entity* childEntity = FindDescendantByName(name);
  668. return childEntity ? childEntity->GetId() : AZ::EntityId();
  669. }
  670. ////////////////////////////////////////////////////////////////////////////////////////////////////
  671. AZ::Entity* UiElementComponent::FindChildByEntityId(AZ::EntityId id)
  672. {
  673. AZ::Entity* matchElem = nullptr;
  674. int numChildren = static_cast<int>(m_childEntityIdOrder.size());
  675. for (int i = 0; i < numChildren; ++i)
  676. {
  677. if (id == m_childEntityIdOrder[i].m_entityId)
  678. {
  679. if (AreChildPointersValid())
  680. {
  681. matchElem = GetChildElementComponent(i)->GetEntity();
  682. }
  683. else
  684. {
  685. AZ::ComponentApplicationBus::BroadcastResult(matchElem, &AZ::ComponentApplicationBus::Events::FindEntity, id);
  686. }
  687. break;
  688. }
  689. }
  690. return matchElem;
  691. }
  692. ////////////////////////////////////////////////////////////////////////////////////////////////////
  693. AZ::Entity* UiElementComponent::FindDescendantById(LyShine::ElementId id)
  694. {
  695. if (id == m_elementId)
  696. {
  697. return GetEntity();
  698. }
  699. AZ::Entity* match = nullptr;
  700. if (AreChildPointersValid())
  701. {
  702. int numChildren = static_cast<int>(m_childEntityIdOrder.size());
  703. for (int i = 0; !match && i < numChildren; ++i)
  704. {
  705. match = GetChildElementComponent(i)->FindDescendantById(id);
  706. }
  707. }
  708. else
  709. {
  710. for (auto iter = m_childEntityIdOrder.begin(); !match && iter != m_childEntityIdOrder.end(); iter++)
  711. {
  712. UiElementBus::EventResult(match, iter->m_entityId, &UiElementBus::Events::FindDescendantById, id);
  713. }
  714. }
  715. return match;
  716. }
  717. ////////////////////////////////////////////////////////////////////////////////////////////////////
  718. void UiElementComponent::FindDescendantElements(AZStd::function<bool(const AZ::Entity*)> predicate, LyShine::EntityArray& result)
  719. {
  720. if (AreChildPointersValid())
  721. {
  722. int numChildren = static_cast<int>(m_childElementComponents.size());
  723. for (int i = 0; i < numChildren; ++i)
  724. {
  725. UiElementComponent* childElementComponent = GetChildElementComponent(i);
  726. AZ::Entity* childEntity = childElementComponent->GetEntity();
  727. if (predicate(childEntity))
  728. {
  729. result.push_back(childEntity);
  730. }
  731. childElementComponent->FindDescendantElements(predicate, result);
  732. }
  733. }
  734. else
  735. {
  736. for (auto& child : m_childEntityIdOrder)
  737. {
  738. AZ::Entity* childEntity = nullptr;
  739. AZ::ComponentApplicationBus::BroadcastResult(childEntity, &AZ::ComponentApplicationBus::Events::FindEntity, child.m_entityId);
  740. if (childEntity && predicate(childEntity))
  741. {
  742. result.push_back(childEntity);
  743. }
  744. UiElementBus::Event(child.m_entityId, &UiElementBus::Events::FindDescendantElements, predicate, result);
  745. }
  746. }
  747. }
  748. ////////////////////////////////////////////////////////////////////////////////////////////////////
  749. void UiElementComponent::CallOnDescendantElements(AZStd::function<void(const AZ::EntityId)> callFunction)
  750. {
  751. if (AreChildPointersValid())
  752. {
  753. int numChildren = static_cast<int>(m_childEntityIdOrder.size());
  754. for (int i = 0; i < numChildren; ++i)
  755. {
  756. callFunction(m_childEntityIdOrder[i].m_entityId);
  757. GetChildElementComponent(i)->CallOnDescendantElements(callFunction);
  758. }
  759. }
  760. else
  761. {
  762. for (auto& child : m_childEntityIdOrder)
  763. {
  764. callFunction(child.m_entityId);
  765. UiElementBus::Event(child.m_entityId, &UiElementBus::Events::CallOnDescendantElements, callFunction);
  766. }
  767. }
  768. }
  769. ////////////////////////////////////////////////////////////////////////////////////////////////////
  770. bool UiElementComponent::IsAncestor(AZ::EntityId id)
  771. {
  772. UiElementComponent* parentElementComponent = GetParentElementComponent();
  773. while (parentElementComponent)
  774. {
  775. if (parentElementComponent->GetEntityId() == id)
  776. {
  777. return true;
  778. }
  779. parentElementComponent = parentElementComponent->GetParentElementComponent();
  780. }
  781. return false;
  782. }
  783. ////////////////////////////////////////////////////////////////////////////////////////////////////
  784. bool UiElementComponent::IsEnabled()
  785. {
  786. return m_isEnabled;
  787. }
  788. ////////////////////////////////////////////////////////////////////////////////////////////////////
  789. void UiElementComponent::SetIsEnabled(bool isEnabled)
  790. {
  791. if (isEnabled != m_isEnabled)
  792. {
  793. m_isEnabled = isEnabled;
  794. // Tell any listeners that the enabled state has changed
  795. UiElementNotificationBus::Event(GetEntityId(), &UiElementNotificationBus::Events::OnUiElementEnabledChanged, m_isEnabled);
  796. // If the ancestors are not enabled then changing the local flag has no effect on the effective
  797. // enabled state.
  798. bool areAncestorsEnabled = (m_parentElementComponent) ? m_parentElementComponent->GetAreElementAndAncestorsEnabled() : true;
  799. if (areAncestorsEnabled)
  800. {
  801. // Tell any listeners that the effective enabled state has changed
  802. UiElementNotificationBus::Event(
  803. GetEntityId(), &UiElementNotificationBus::Events::OnUiElementAndAncestorsEnabledChanged, m_isEnabled);
  804. DoRecursiveEnabledNotification(m_isEnabled);
  805. }
  806. // tell the canvas to invalidate the render graph
  807. if (m_canvas)
  808. {
  809. m_canvas->MarkRenderGraphDirty();
  810. }
  811. }
  812. }
  813. ////////////////////////////////////////////////////////////////////////////////////////////////////
  814. bool UiElementComponent::GetAreElementAndAncestorsEnabled()
  815. {
  816. if (!m_isEnabled)
  817. {
  818. return false;
  819. }
  820. if (m_parentElementComponent)
  821. {
  822. return m_parentElementComponent->GetAreElementAndAncestorsEnabled();
  823. }
  824. return true;
  825. }
  826. ////////////////////////////////////////////////////////////////////////////////////////////////////
  827. bool UiElementComponent::IsRenderEnabled()
  828. {
  829. return m_isRenderEnabled;
  830. }
  831. ////////////////////////////////////////////////////////////////////////////////////////////////////
  832. void UiElementComponent::SetIsRenderEnabled(bool isRenderEnabled)
  833. {
  834. m_isRenderEnabled = isRenderEnabled;
  835. }
  836. ////////////////////////////////////////////////////////////////////////////////////////////////////
  837. bool UiElementComponent::GetIsVisible()
  838. {
  839. return m_isVisibleInEditor;
  840. }
  841. ////////////////////////////////////////////////////////////////////////////////////////////////////
  842. void UiElementComponent::SetIsVisible(bool isVisible)
  843. {
  844. if (m_isVisibleInEditor != isVisible)
  845. {
  846. m_isVisibleInEditor = isVisible;
  847. if (m_canvas)
  848. {
  849. // we have to regenerate the graph because different elements are now visible
  850. m_canvas->MarkRenderGraphDirty();
  851. }
  852. }
  853. }
  854. ////////////////////////////////////////////////////////////////////////////////////////////////////
  855. bool UiElementComponent::GetIsSelectable()
  856. {
  857. return m_isSelectableInEditor;
  858. }
  859. ////////////////////////////////////////////////////////////////////////////////////////////////////
  860. void UiElementComponent::SetIsSelectable(bool isSelectable)
  861. {
  862. m_isSelectableInEditor = isSelectable;
  863. }
  864. ////////////////////////////////////////////////////////////////////////////////////////////////////
  865. bool UiElementComponent::GetIsSelected()
  866. {
  867. return m_isSelectedInEditor;
  868. }
  869. ////////////////////////////////////////////////////////////////////////////////////////////////////
  870. void UiElementComponent::SetIsSelected(bool isSelected)
  871. {
  872. m_isSelectedInEditor = isSelected;
  873. }
  874. ////////////////////////////////////////////////////////////////////////////////////////////////////
  875. bool UiElementComponent::GetIsExpanded()
  876. {
  877. return m_isExpandedInEditor;
  878. }
  879. ////////////////////////////////////////////////////////////////////////////////////////////////////
  880. void UiElementComponent::SetIsExpanded(bool isExpanded)
  881. {
  882. m_isExpandedInEditor = isExpanded;
  883. }
  884. ////////////////////////////////////////////////////////////////////////////////////////////////////
  885. bool UiElementComponent::AreAllAncestorsVisible()
  886. {
  887. UiElementComponent* parentElementComponent = GetParentElementComponent();
  888. while (parentElementComponent)
  889. {
  890. bool isParentVisible = true;
  891. UiEditorBus::EventResult(isParentVisible, parentElementComponent->GetEntityId(), &UiEditorBus::Events::GetIsVisible);
  892. if (!isParentVisible)
  893. {
  894. return false;
  895. }
  896. // Walk up the hierarchy.
  897. parentElementComponent = parentElementComponent->GetParentElementComponent();
  898. }
  899. // there is no ancestor entity that is not visible
  900. return true;
  901. }
  902. ////////////////////////////////////////////////////////////////////////////////////////////////////
  903. void UiElementComponent::OnEntityActivated(const AZ::EntityId&)
  904. {
  905. // cache pointers to the optional render interface and render control interface to
  906. // optimize calls rather than using ebus. Both of these buses only allow single handlers.
  907. m_renderInterface = UiRenderBus::FindFirstHandler(GetEntityId());
  908. m_renderControlInterface = UiRenderControlBus::FindFirstHandler(GetEntityId());
  909. }
  910. ////////////////////////////////////////////////////////////////////////////////////////////////////
  911. void UiElementComponent::OnEntityDeactivated(const AZ::EntityId&)
  912. {
  913. m_renderInterface = nullptr;
  914. m_renderControlInterface = nullptr;
  915. }
  916. ////////////////////////////////////////////////////////////////////////////////////////////////////
  917. void UiElementComponent::AddChild(AZ::Entity* child, AZ::Entity* insertBefore)
  918. {
  919. // debug check that this element is not already a child
  920. AZ_Assert(FindChildByEntityId(child->GetId()) == nullptr, "Attempting to add a duplicate child");
  921. UiElementComponent* childElementComponent = child->FindComponent<UiElementComponent>();
  922. AZ_Assert(childElementComponent, "Attempting to add a child with no element component");
  923. if (!childElementComponent)
  924. {
  925. return;
  926. }
  927. bool wasInserted = false;
  928. if (insertBefore)
  929. {
  930. int numChildren = static_cast<int>(m_childEntityIdOrder.size());
  931. for (int i = 0; i < numChildren; ++i)
  932. {
  933. if (m_childEntityIdOrder[i].m_entityId == insertBefore->GetId())
  934. {
  935. if (AreChildPointersValid()) // must test before m_childEntityIdOrder.insert
  936. {
  937. m_childElementComponents.insert(m_childElementComponents.begin() + i, childElementComponent);
  938. }
  939. m_childEntityIdOrder.insert(m_childEntityIdOrder.begin() + i, {child->GetId(), static_cast<AZ::u64>(i)});
  940. ResetChildEntityIdSortOrders();
  941. wasInserted = true;
  942. break;
  943. }
  944. }
  945. }
  946. // either insertBefore is null or it is not found, insert at end
  947. if (!wasInserted)
  948. {
  949. if (AreChildPointersValid()) // must test before m_childEntityIdOrder.push_back
  950. {
  951. m_childElementComponents.push_back(childElementComponent);
  952. }
  953. m_childEntityIdOrder.push_back({child->GetId(), m_childEntityIdOrder.size()});
  954. }
  955. // Adding or removing child elements may require recomputing the
  956. // transforms of all children
  957. UiLayoutManagerBus::Event(GetCanvasEntityId(), &UiLayoutManagerBus::Events::MarkToRecomputeLayout, GetEntityId());
  958. UiLayoutManagerBus::Event(
  959. GetCanvasEntityId(), &UiLayoutManagerBus::Events::MarkToRecomputeLayoutsAffectedByLayoutCellChange, GetEntityId(), false);
  960. // It will always require recomputing the transform for the child just added
  961. if (IsFullyInitialized())
  962. {
  963. GetTransform2dComponent()->SetRecomputeFlags(UiTransformInterface::Recompute::RectAndTransform);
  964. }
  965. // tell the canvas to invalidate the render graph
  966. if (m_canvas)
  967. {
  968. m_canvas->MarkRenderGraphDirty();
  969. }
  970. }
  971. ////////////////////////////////////////////////////////////////////////////////////////////////////
  972. void UiElementComponent::RemoveChild(AZ::Entity* child)
  973. {
  974. // check if the given entity is actually a child, if not then do nothing
  975. AZ::EntityId childId = child->GetId();
  976. auto iter = AZStd::find_if(m_childEntityIdOrder.begin(), m_childEntityIdOrder.end(),
  977. [childId](ChildEntityIdOrderEntry& entry) { return entry.m_entityId == childId; });
  978. if (iter != m_childEntityIdOrder.end())
  979. {
  980. // remove the child from m_childEntityIdOrder
  981. m_childEntityIdOrder.erase(iter);
  982. // update the sort indices to be contiguous
  983. ResetChildEntityIdSortOrders();
  984. UiElementComponent* elementComponent = child->FindComponent<UiElementComponent>();
  985. AZ_Assert(elementComponent, "Child element has no UiElementComponent");
  986. // Also erase from m_childElementComponents
  987. stl::find_and_erase(m_childElementComponents, elementComponent);
  988. // Clear child's parent
  989. elementComponent->SetParentReferences(nullptr, nullptr);
  990. // Adding or removing child elements may require recomputing the
  991. // transforms of all children
  992. UiLayoutManagerBus::Event(GetCanvasEntityId(), &UiLayoutManagerBus::Events::MarkToRecomputeLayout, GetEntityId());
  993. UiLayoutManagerBus::Event(
  994. GetCanvasEntityId(), &UiLayoutManagerBus::Events::MarkToRecomputeLayoutsAffectedByLayoutCellChange, GetEntityId(), false);
  995. // tell the canvas to invalidate the render graph
  996. if (m_canvas)
  997. {
  998. m_canvas->MarkRenderGraphDirty();
  999. }
  1000. }
  1001. }
  1002. ////////////////////////////////////////////////////////////////////////////////////////////////////
  1003. void UiElementComponent::RemoveChild(AZ::EntityId child)
  1004. {
  1005. AZ::EntityId childId = child;
  1006. auto iter = AZStd::find_if(m_childEntityIdOrder.begin(), m_childEntityIdOrder.end(),
  1007. [childId](ChildEntityIdOrderEntry& entry) { return entry.m_entityId == childId; });
  1008. if (iter != m_childEntityIdOrder.end())
  1009. {
  1010. if (AreChildPointersValid())
  1011. {
  1012. auto childElementiter = AZStd::find_if(m_childElementComponents.begin(), m_childElementComponents.end(),
  1013. [childId](UiElementComponent* elementComponent) { return elementComponent->GetEntityId() == childId; });
  1014. UiElementComponent* elementComponent = childElementiter != m_childElementComponents.end() ? *childElementiter : nullptr;
  1015. AZ_Assert(elementComponent, "");
  1016. if (elementComponent)
  1017. {
  1018. stl::find_and_erase(m_childElementComponents, elementComponent);
  1019. // Clear child's parent
  1020. elementComponent->SetParentReferences(nullptr, nullptr);
  1021. }
  1022. }
  1023. // remove the child from m_childEntityIdOrder
  1024. m_childEntityIdOrder.erase(iter);
  1025. // update the sort indicies to be contiguous
  1026. ResetChildEntityIdSortOrders();
  1027. // Adding or removing child elements may require recomputing the
  1028. // transforms of all children
  1029. UiLayoutManagerBus::Event(GetCanvasEntityId(), &UiLayoutManagerBus::Events::MarkToRecomputeLayout, GetEntityId());
  1030. UiLayoutManagerBus::Event(
  1031. GetCanvasEntityId(), &UiLayoutManagerBus::Events::MarkToRecomputeLayoutsAffectedByLayoutCellChange, GetEntityId(), false);
  1032. // tell the canvas to invalidate the render graph
  1033. if (m_canvas)
  1034. {
  1035. m_canvas->MarkRenderGraphDirty();
  1036. }
  1037. }
  1038. }
  1039. ////////////////////////////////////////////////////////////////////////////////////////////////////
  1040. void UiElementComponent::SetCanvas(UiCanvasComponent* canvas, LyShine::ElementId elementId)
  1041. {
  1042. m_canvas = canvas;
  1043. m_elementId = elementId;
  1044. }
  1045. ////////////////////////////////////////////////////////////////////////////////////////////////////
  1046. bool UiElementComponent::FixupPostLoad(AZ::Entity* entity, UiCanvasComponent* canvas, AZ::Entity* parent, bool makeNewElementIds)
  1047. {
  1048. #ifdef AZ_DEBUG_BUILD
  1049. // check that the m_childEntityIdOrder is ordered such that the m_sortIndex fields are in order and contiguous
  1050. {
  1051. size_t numChildren = m_childEntityIdOrder.size();
  1052. for (size_t index = 0; index < numChildren; ++index)
  1053. {
  1054. if (m_childEntityIdOrder[index].m_sortIndex != index)
  1055. {
  1056. AZ_Assert(false, "FixupPostLoad: m_childEntityIdOrder bad sort index. This should never happen.");
  1057. }
  1058. }
  1059. }
  1060. #endif
  1061. if (makeNewElementIds)
  1062. {
  1063. m_elementId = canvas->GenerateId();
  1064. }
  1065. m_canvas = canvas;
  1066. if (parent)
  1067. {
  1068. UiElementComponent* parentElementComponent = parent->FindComponent<UiElementComponent>();
  1069. AZ_Assert(parentElementComponent, "Parent element has no UiElementComponent");
  1070. SetParentReferences(parent, parentElementComponent);
  1071. }
  1072. else
  1073. {
  1074. SetParentReferences(nullptr, nullptr);
  1075. }
  1076. ChildEntityIdOrderArray missingChildren;
  1077. for (auto& child : m_childEntityIdOrder)
  1078. {
  1079. AZ::Entity* childEntity = nullptr;
  1080. AZ::ComponentApplicationBus::BroadcastResult(childEntity, &AZ::ComponentApplicationBus::Events::FindEntity, child.m_entityId);
  1081. if (!childEntity)
  1082. {
  1083. // with slices it is possible for users to get themselves into situations where a child no
  1084. // longer exists, we should report an error in this case rather than asserting
  1085. AZ_Error("UI", false, "Child element with Entity ID %llu no longer exists. Data will be lost.", child);
  1086. // This case could happen if a slice asset has been deleted. We should try to continue and load the
  1087. // canvas with errors.
  1088. missingChildren.push_back(child);
  1089. continue;
  1090. }
  1091. UiElementComponent* elementComponent = childEntity->FindComponent<UiElementComponent>();
  1092. if (!elementComponent)
  1093. {
  1094. // with slices it is possible for users to get themselves into situations where a child no
  1095. // longer has an element component. In this case report an error and fail to load the data but do not
  1096. // crash.
  1097. AZ_Error("UI", false, "Child element with Entity ID %llu no longer has a UiElementComponent. Data cannot be loaded.", child);
  1098. return false;
  1099. }
  1100. bool success = elementComponent->FixupPostLoad(childEntity, canvas, entity, makeNewElementIds);
  1101. if (!success)
  1102. {
  1103. return false;
  1104. }
  1105. }
  1106. // If there were any missing children remove them from the m_childEntityIdOrder list
  1107. // This is recovery code for the case that a slice asset that we were using has been removed.
  1108. for (auto child : missingChildren)
  1109. {
  1110. stl::find_and_erase(m_childEntityIdOrder, child);
  1111. }
  1112. // Initialize the m_childElementComponents array that is used for performance optimization
  1113. m_childElementComponents.clear();
  1114. for (auto child : m_childEntityIdOrder)
  1115. {
  1116. AZ::Entity* childEntity = nullptr;
  1117. AZ::ComponentApplicationBus::BroadcastResult(childEntity, &AZ::ComponentApplicationBus::Events::FindEntity, child.m_entityId);
  1118. AZ_Assert(childEntity, "Child element not found");
  1119. UiElementComponent* childElementComponent = childEntity->FindComponent<UiElementComponent>();
  1120. AZ_Assert(childElementComponent, "Child element has no UiElementComponent");
  1121. m_childElementComponents.push_back(childElementComponent);
  1122. }
  1123. // Tell any listeners that the canvas entity ID for the element is now set, this allows other components to
  1124. // listen for messages from the canvas
  1125. AZ::EntityId parentEntityId = (parent) ? parent->GetId() : AZ::EntityId();
  1126. UiElementNotificationBus::Event(
  1127. GetEntityId(), &UiElementNotificationBus::Events::OnUiElementFixup, canvas->GetEntityId(), parentEntityId);
  1128. return true;
  1129. }
  1130. ////////////////////////////////////////////////////////////////////////////////////////////////////
  1131. AZ::EntityId UiElementComponent::GetSliceEntityParentId()
  1132. {
  1133. return GetParentEntityId();
  1134. }
  1135. AZStd::vector<AZ::EntityId> UiElementComponent::GetSliceEntityChildren()
  1136. {
  1137. return GetChildEntityIds();
  1138. }
  1139. ////////////////////////////////////////////////////////////////////////////////////////////////////
  1140. // PUBLIC STATIC MEMBER FUNCTIONS
  1141. ////////////////////////////////////////////////////////////////////////////////////////////////////
  1142. void UiElementComponent::Reflect(AZ::ReflectContext* context)
  1143. {
  1144. AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
  1145. if (serializeContext)
  1146. {
  1147. serializeContext->Class<ChildEntityIdOrderEntry>()
  1148. // Persistent IDs for this are simply the entity id
  1149. ->PersistentId([](const void* instance) -> AZ::u64
  1150. {
  1151. const ChildEntityIdOrderEntry* entry = reinterpret_cast<const ChildEntityIdOrderEntry*>(instance);
  1152. return static_cast<AZ::u64>(entry->m_entityId);
  1153. })
  1154. ->Version(1)
  1155. ->Field("ChildEntityId", &ChildEntityIdOrderEntry::m_entityId)
  1156. ->Field("SortIndex", &ChildEntityIdOrderEntry::m_sortIndex);
  1157. serializeContext->Class<UiElementComponent, AZ::Component>()
  1158. ->Version(3, &VersionConverter)
  1159. ->EventHandler<ChildOrderSerializationEvents>()
  1160. ->Field("Id", &UiElementComponent::m_elementId)
  1161. ->Field("IsEnabled", &UiElementComponent::m_isEnabled)
  1162. ->Field("IsVisibleInEditor", &UiElementComponent::m_isVisibleInEditor)
  1163. ->Field("IsSelectableInEditor", &UiElementComponent::m_isSelectableInEditor)
  1164. ->Field("IsSelectedInEditor", &UiElementComponent::m_isSelectedInEditor)
  1165. ->Field("IsExpandedInEditor", &UiElementComponent::m_isExpandedInEditor)
  1166. ->Field("ChildEntityIdOrder", &UiElementComponent::m_childEntityIdOrder);
  1167. AZ::EditContext* ec = serializeContext->GetEditContext();
  1168. if (ec)
  1169. {
  1170. auto editInfo = ec->Class<UiElementComponent>("Element", "Adds UI Element behavior to an entity");
  1171. editInfo->ClassElement(AZ::Edit::ClassElements::EditorData, "")
  1172. ->Attribute(AZ::Edit::Attributes::Icon, "Editor/Icons/Components/UiElement.png")
  1173. ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Editor/Icons/Components/Viewport/UiElement.png")
  1174. ->Attribute(AZ::Edit::Attributes::AddableByUser, false) // Cannot be added or removed by user
  1175. ->Attribute(AZ::Edit::Attributes::AutoExpand, true);
  1176. editInfo->DataElement("String", &UiElementComponent::m_elementId, "Id",
  1177. "This read-only ID is used to reference the element from FlowGraph")
  1178. ->Attribute(AZ::Edit::Attributes::ReadOnly, true)
  1179. ->Attribute(AZ::Edit::Attributes::SliceFlags, AZ::Edit::SliceFlags::NotPushable);
  1180. editInfo->DataElement(0, &UiElementComponent::m_isEnabled, "Start enabled",
  1181. "Determines whether the element is enabled upon creation.\n"
  1182. "If an element is not enabled, neither it nor any of its children are drawn or interactive.");
  1183. // These are not visible in the PropertyGrid since they are managed through the Hierarchy Pane
  1184. // We do want to be able to push them to a slice though.
  1185. editInfo->DataElement(0, &UiElementComponent::m_isVisibleInEditor, "IsVisibleInEditor", "")
  1186. ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::Hide);
  1187. editInfo->DataElement(0, &UiElementComponent::m_isSelectableInEditor, "IsSelectableInEditor", "")
  1188. ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::Hide);
  1189. editInfo->DataElement(0, &UiElementComponent::m_isExpandedInEditor, "IsExpandedInEditor", "")
  1190. ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::Hide);
  1191. }
  1192. }
  1193. AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context);
  1194. if (behaviorContext)
  1195. {
  1196. behaviorContext->EBus<UiElementBus>("UiElementBus")
  1197. ->Event("GetName", &UiElementBus::Events::GetName)
  1198. ->Event("GetCanvas", &UiElementBus::Events::GetCanvasEntityId)
  1199. ->Event("GetParent", &UiElementBus::Events::GetParentEntityId)
  1200. ->Event("GetNumChildElements", &UiElementBus::Events::GetNumChildElements)
  1201. ->Event("GetChild", &UiElementBus::Events::GetChildEntityId)
  1202. ->Event("GetIndexOfChildByEntityId", &UiElementBus::Events::GetIndexOfChildByEntityId)
  1203. ->Event("GetChildren", &UiElementBus::Events::GetChildEntityIds)
  1204. ->Event("DestroyElement", &UiElementBus::Events::DestroyElementOnFrameEnd)
  1205. ->Event("Reparent", &UiElementBus::Events::ReparentByEntityId)
  1206. ->Event("FindChildByName", &UiElementBus::Events::FindChildEntityIdByName)
  1207. ->Event("FindDescendantByName", &UiElementBus::Events::FindDescendantEntityIdByName)
  1208. ->Event("IsAncestor", &UiElementBus::Events::IsAncestor)
  1209. ->Event("IsEnabled", &UiElementBus::Events::IsEnabled)
  1210. ->Event("SetIsEnabled", &UiElementBus::Events::SetIsEnabled);
  1211. }
  1212. }
  1213. ////////////////////////////////////////////////////////////////////////////////////////////////////
  1214. void UiElementComponent::Initialize()
  1215. {
  1216. }
  1217. ////////////////////////////////////////////////////////////////////////////////////////////////////
  1218. bool UiElementComponent::MoveEntityAndDescendantsToListAndReplaceWithEntityId(AZ::SerializeContext& context,
  1219. AZ::SerializeContext::DataElementNode& elementNode,
  1220. int index,
  1221. AZStd::vector<AZ::SerializeContext::DataElementNode>& entities)
  1222. {
  1223. // Find the UiElementComponent on this entity
  1224. AZ::SerializeContext::DataElementNode* elementComponentNode =
  1225. LyShine::FindComponentNode(elementNode, UiElementComponent::TYPEINFO_Uuid());
  1226. if (!elementComponentNode)
  1227. {
  1228. return false;
  1229. }
  1230. // We must process the children first so that when we make a copy of this entity to the entities list
  1231. // it will already have had its child entities replaced with entity IDs
  1232. // find the m_children field
  1233. int childrenIndex = elementComponentNode->FindElement(AZ_CRC("Children", 0xa197b1ba));
  1234. if (childrenIndex == -1)
  1235. {
  1236. return false;
  1237. }
  1238. AZ::SerializeContext::DataElementNode& childrenNode = elementComponentNode->GetSubElement(childrenIndex);
  1239. // Create the child entities member (which is a generic vector)
  1240. AZ::SerializeContext::ClassData* classData = AZ::SerializeGenericTypeInfo<ChildEntityIdOrderArray>::GetGenericInfo()->GetClassData();
  1241. int newChildrenIndex = elementComponentNode->AddElement(context, "ChildEntityIdOrder", *classData);
  1242. if (newChildrenIndex == -1)
  1243. {
  1244. return false;
  1245. }
  1246. AZ::SerializeContext::DataElementNode& newChildrenNode = elementComponentNode->GetSubElement(newChildrenIndex);
  1247. // iterate through children and recursively call this function
  1248. int numChildren = childrenNode.GetNumSubElements();
  1249. for (int childIndex = 0; childIndex < numChildren; ++childIndex)
  1250. {
  1251. AZ::SerializeContext::DataElementNode& childElementNode = childrenNode.GetSubElement(childIndex);
  1252. MoveEntityAndDescendantsToListAndReplaceWithEntityId(context, childElementNode, childIndex, entities);
  1253. newChildrenNode.AddElement(childElementNode);
  1254. }
  1255. // delete the original "Children" node, we have replaced it with the "ChildEntityIdOrder" node
  1256. elementComponentNode->RemoveElement(childrenIndex);
  1257. // the children list has now been processed so it will now just contain entity IDs
  1258. // Now copy this node (elementNode) to the list we are building and then replace it
  1259. // with an Entity ID node
  1260. // copy this node to the list
  1261. entities.push_back(elementNode);
  1262. // Remember the name of this node (it could be "element" or "RootElement" for example)
  1263. AZStd::string elementFieldName = elementNode.GetNameString();
  1264. // Find the EntityId node within this entity
  1265. int entityIdIndex = elementNode.FindElement(AZ_CRC("Id", 0xbf396750));
  1266. if (entityIdIndex == -1)
  1267. {
  1268. return false;
  1269. }
  1270. AZ::SerializeContext::DataElementNode& elementIdNode = elementNode.GetSubElement(entityIdIndex);
  1271. // Find the sub node of the EntityID that actually stores the u64 and make a copy of it
  1272. int u64Index = elementIdNode.FindElement(AZ_CRC("id", 0xbf396750));
  1273. if (u64Index == -1)
  1274. {
  1275. return false;
  1276. }
  1277. AZ::SerializeContext::DataElementNode u64Node = elementIdNode.GetSubElement(u64Index);
  1278. // -1 indicates this is the root element reference
  1279. if (index == -1)
  1280. {
  1281. // Convert this node (which was an entire Entity) into just an EntityId, keeping the same
  1282. // node name as it had
  1283. elementNode.Convert<AZ::EntityId>(context, elementFieldName.c_str());
  1284. // copy in the subNode that stores the actual u64 (that we saved a copy of above)
  1285. elementNode.AddElement(u64Node);
  1286. }
  1287. else
  1288. {
  1289. // Convert this node (which was an entire Entity) into just an ChildEntityIdOrderEntry, keeping the same
  1290. // node name as it had
  1291. elementNode.Convert<ChildEntityIdOrderEntry>(context, elementFieldName.c_str());
  1292. // add sub element from the entity Id
  1293. int childOrderEntryEntityIdIndex = elementNode.AddElement<AZ::EntityId>(context, "ChildEntityId");
  1294. AZ::SerializeContext::DataElementNode& childOrderEntryEntityIdElementNode = elementNode.GetSubElement(childOrderEntryEntityIdIndex);
  1295. // copy in the subNode that stores the actual u64 (that we saved a copy of above)
  1296. childOrderEntryEntityIdElementNode.AddElement(u64Node);
  1297. AZ::u64 sortIndex = static_cast<AZ::u64>(index);
  1298. elementNode.AddElementWithData<AZ::u64>(context, "SortIndex", sortIndex);
  1299. }
  1300. return true;
  1301. }
  1302. ////////////////////////////////////////////////////////////////////////////////////////////////////
  1303. // PROTECTED MEMBER FUNCTIONS
  1304. ////////////////////////////////////////////////////////////////////////////////////////////////////
  1305. ////////////////////////////////////////////////////////////////////////////////////////////////////
  1306. void UiElementComponent::Activate()
  1307. {
  1308. UiElementBus::Handler::BusConnect(m_entity->GetId());
  1309. UiEditorBus::Handler::BusConnect(m_entity->GetId());
  1310. AZ::SliceEntityHierarchyRequestBus::Handler::BusConnect(m_entity->GetId());
  1311. AZ::EntityBus::Handler::BusConnect(m_entity->GetId());
  1312. // Once added the transform component is never removed
  1313. if (!m_transformComponent)
  1314. {
  1315. m_transformComponent = GetEntity()->FindComponent<UiTransform2dComponent>();
  1316. }
  1317. // tell the canvas to invalidate the render graph
  1318. if (m_canvas)
  1319. {
  1320. m_canvas->MarkRenderGraphDirty();
  1321. }
  1322. }
  1323. ////////////////////////////////////////////////////////////////////////////////////////////////////
  1324. void UiElementComponent::Deactivate()
  1325. {
  1326. UiElementBus::Handler::BusDisconnect();
  1327. UiEditorBus::Handler::BusDisconnect();
  1328. AZ::SliceEntityHierarchyRequestBus::Handler::BusDisconnect();
  1329. AZ::EntityBus::Handler::BusDisconnect();
  1330. // tell the canvas to invalidate the render graph
  1331. if (m_canvas)
  1332. {
  1333. m_canvas->MarkRenderGraphDirty();
  1334. }
  1335. }
  1336. ////////////////////////////////////////////////////////////////////////////////////////////////////
  1337. void UiElementComponent::DoRecursiveEnabledNotification(bool newIsEnabledValue)
  1338. {
  1339. for (UiElementComponent* child : m_childElementComponents)
  1340. {
  1341. // if this child element is disabled then the enabled state of the ancestors makes no difference
  1342. // but if it is enabled then its effective enabled state is controlled by its ancestors
  1343. if (child->m_isEnabled)
  1344. {
  1345. UiElementNotificationBus::Event(
  1346. child->GetEntityId(), &UiElementNotificationBus::Events::OnUiElementAndAncestorsEnabledChanged, newIsEnabledValue);
  1347. child->DoRecursiveEnabledNotification(newIsEnabledValue);
  1348. }
  1349. }
  1350. }
  1351. ////////////////////////////////////////////////////////////////////////////////////////////////////
  1352. // PRIVATE MEMBER FUNCTIONS
  1353. ////////////////////////////////////////////////////////////////////////////////////////////////////
  1354. ////////////////////////////////////////////////////////////////////////////////////////////////////
  1355. void UiElementComponent::EmitNotInitializedWarning() const
  1356. {
  1357. AZ_Warning("UI", false, "UiElementComponent used before fully initialized, possibly on activate before FixupPostLoad was called on this element")
  1358. }
  1359. ////////////////////////////////////////////////////////////////////////////////////////////////////
  1360. void UiElementComponent::SetParentReferences(AZ::Entity* parent, UiElementComponent* parentElementComponent)
  1361. {
  1362. m_parent = parent;
  1363. m_parentId = (parent) ? parent->GetId() : AZ::EntityId();
  1364. m_parentElementComponent = parentElementComponent;
  1365. }
  1366. ////////////////////////////////////////////////////////////////////////////////////////////////////
  1367. void UiElementComponent::OnPatchEnd(const AZ::DataPatchNodeInfo& patchInfo)
  1368. {
  1369. // We want to check the data patch for any patching of the "Children" element. The m_children element no
  1370. // longer exists so we want to make the equivalent changes to the m_childEntityIdOrder element.
  1371. // The relevant patch addresses can be either
  1372. // a) a change of an element in the container
  1373. // b) a removal of an element in the container (these are always higher indices than the changes)
  1374. // c) an addition of an element in the container (these are not always in ascending order, it is an unordered map)
  1375. // (these are always higher indices than the changes)
  1376. //
  1377. // For a given patch there will never be both addition and removals.
  1378. //
  1379. // For b and c the patch address (in childPatchLookup) will be patchinfo.address + "Children".
  1380. // We could find all of those through one call to "find" on childPatchLookup with that address.
  1381. // However, for the "a" case the address (in childPatchLookup) will have an additional element on
  1382. // the end - since it is the "Id" field within the EntityId that is being patched.
  1383. // So we have to iterate through childPatchLookup anyway, so we do that for all cases.
  1384. using EntityIndexPair = AZStd::pair<AZ::u64, AZ::EntityId>;
  1385. using EntityIndexPairList = AZStd::vector<EntityIndexPair>;
  1386. EntityIndexPairList elementsChanged;
  1387. EntityIndexPairList elementsAdded;
  1388. AZStd::vector<AZ::u64> elementsRemoved;
  1389. bool oldChildrenDataPatchFound = false;
  1390. const AZ::DataPatch::AddressType& address = patchInfo.address;
  1391. const AZ::DataPatch::PatchMap& patch = patchInfo.patch;
  1392. const AZ::DataPatch::ChildPatchMap& childPatchLookup = patchInfo.childPatchLookup;
  1393. // Build the address of the "Children" element within this UiElementComponent
  1394. AZ::DataPatch::AddressType childrenAddress = address;
  1395. childrenAddress.push_back(AZ_CRC("Children", 0xa197b1ba));
  1396. // Get the serialize context for use in the LoadObjectFromStreamInPlace calls
  1397. AZ::SerializeContext* serializeContext = nullptr;
  1398. AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext);
  1399. // childPatchLookup contains all addresses in the patch that are within the UiElementComponent so
  1400. // it is slightly faster to iterate over that than over "patch" directly.
  1401. for (auto& childPatchPair : childPatchLookup)
  1402. {
  1403. const AZ::DataPatch::AddressType& lookupAddress = childPatchPair.first;
  1404. if (lookupAddress == childrenAddress)
  1405. {
  1406. // The address matches the "Children" container exactly, so get childPatches which will contain
  1407. // all the additions and removals to the container.
  1408. const AZStd::vector<AZ::DataPatch::AddressType>& childPatches = childPatchPair.second;
  1409. for (auto& childPatchAddress : childPatches)
  1410. {
  1411. auto foundPatchIt = patch.find(childPatchAddress);
  1412. if (foundPatchIt == patch.end())
  1413. {
  1414. // this should never happen, ignore it if it does
  1415. continue;
  1416. }
  1417. // the last part of the address is the index in the m_children array
  1418. AZ::u64 index = childPatchAddress.back().GetAddressElement();
  1419. if (foundPatchIt->second.empty())
  1420. {
  1421. // this is removal of element (actual patch is empty)
  1422. oldChildrenDataPatchFound = true;
  1423. elementsRemoved.push_back(index);
  1424. }
  1425. else
  1426. {
  1427. // This is an addition
  1428. // get the EntityId out of the patch value
  1429. AZ::EntityId entityId;
  1430. bool entityIdLoaded = false;
  1431. // If the patch originated in a Legacy DataPatch then we must first load the EntityId from the legacy stream
  1432. if (foundPatchIt->second.type() == azrtti_typeid<AZ::DataPatch::LegacyStreamWrapper>())
  1433. {
  1434. const AZ::DataPatch::LegacyStreamWrapper* wrapper = AZStd::any_cast<AZ::DataPatch::LegacyStreamWrapper>(&foundPatchIt->second);
  1435. if (wrapper)
  1436. {
  1437. AZ::IO::MemoryStream stream(wrapper->m_stream.data(), wrapper->m_stream.size());
  1438. entityIdLoaded = AZ::Utils::LoadObjectFromStreamInPlace<AZ::EntityId>(stream, entityId, serializeContext);
  1439. }
  1440. }
  1441. else
  1442. {
  1443. // Otherwise we can acquire the EntityId from the patch directly
  1444. const AZ::EntityId* entityIdPtr = AZStd::any_cast<AZ::EntityId>(&foundPatchIt->second);
  1445. if (entityIdPtr)
  1446. {
  1447. entityId = *entityIdPtr;
  1448. entityIdLoaded = true;
  1449. }
  1450. }
  1451. if (entityIdLoaded)
  1452. {
  1453. oldChildrenDataPatchFound = true;
  1454. elementsAdded.push_back({index, entityId});
  1455. }
  1456. else
  1457. {
  1458. AZ_Error("UI", false, "UiElement::OnPatchEnd: Failed to load a child entity Id from DataPatch");
  1459. }
  1460. }
  1461. }
  1462. }
  1463. else if (lookupAddress.size() == childrenAddress.size() + 1)
  1464. {
  1465. // the lookupAddress is the same length as the "Children" address plus an index
  1466. // check if the address is childrenAddress plus an extra element
  1467. bool match = true;
  1468. for (int i = static_cast<int>(childrenAddress.size() - 1); i >= 0; --i)
  1469. {
  1470. if (lookupAddress[i] != childrenAddress[i])
  1471. {
  1472. match = false;
  1473. break;
  1474. }
  1475. }
  1476. if (!match)
  1477. {
  1478. continue;
  1479. }
  1480. // childPatches will be any patches to this one element in the children array (should only ever be one element in the map)
  1481. const AZStd::vector<AZ::DataPatch::AddressType>& childPatches = childPatchPair.second;
  1482. for (auto& childPatchAddress : childPatches)
  1483. {
  1484. auto foundPatchIt = patch.find(childPatchAddress);
  1485. if (foundPatchIt == patch.end())
  1486. {
  1487. // this should never happen, ignore it if it does
  1488. continue;
  1489. }
  1490. if (foundPatchIt->second.empty())
  1491. {
  1492. // this is removal of element (actual patch is empty). Should never occur in this path. Ignore.
  1493. continue;
  1494. }
  1495. // This should be the u64 "Id" element of the EntityId, if not ignore.
  1496. if (childPatchAddress.back().GetAddressElement() == AZ_CRC("Id", 0xbf396750))
  1497. {
  1498. // the second to last part of the address is the index in the m_children array
  1499. AZ::u64 index = childPatchAddress[childPatchAddress.size() - 2].GetAddressElement();
  1500. // extract the u64 from the patch value
  1501. AZ::u64 id = 0;
  1502. bool idLoaded = false;
  1503. // If the patch originated in a Legacy DataPatch then we must first load the u64 from the legacy stream
  1504. if (foundPatchIt->second.type() == azrtti_typeid<AZ::DataPatch::LegacyStreamWrapper>())
  1505. {
  1506. const AZ::DataPatch::LegacyStreamWrapper* wrapper = AZStd::any_cast<AZ::DataPatch::LegacyStreamWrapper>(&foundPatchIt->second);
  1507. if (wrapper)
  1508. {
  1509. AZ::IO::MemoryStream stream(wrapper->m_stream.data(), wrapper->m_stream.size());
  1510. idLoaded = AZ::Utils::LoadObjectFromStreamInPlace<AZ::u64>(stream, id, serializeContext);
  1511. }
  1512. }
  1513. else
  1514. {
  1515. // Otherwise we can acquire the EntityId from the patch directly
  1516. const AZ::u64* idPtr = AZStd::any_cast<AZ::u64>(&foundPatchIt->second);
  1517. if (idPtr)
  1518. {
  1519. id = *idPtr;
  1520. idLoaded = true;
  1521. }
  1522. }
  1523. if (idLoaded)
  1524. {
  1525. AZ::EntityId entityId(id);
  1526. oldChildrenDataPatchFound = true;
  1527. elementsChanged.push_back({index, entityId});
  1528. }
  1529. else
  1530. {
  1531. AZ_Error("UI", false, "UiElement::OnPatchEnd: Failed to load a child entity Id from DataPatch");
  1532. }
  1533. }
  1534. }
  1535. }
  1536. }
  1537. // if patch data for the old "Children" container was found then apply it to the new m_childEntityIdOrder vector
  1538. if (oldChildrenDataPatchFound)
  1539. {
  1540. if (elementsAdded.size() > 0 && elementsRemoved.size() > 0)
  1541. {
  1542. AZ_Error("UI", false, "OnPatchEnd: can't add and remove in the same patch");
  1543. }
  1544. // removing elements always removes from the end. So we just need to resize to the lowest index
  1545. for (AZ::u64 index : elementsRemoved)
  1546. {
  1547. if (index < m_childEntityIdOrder.size())
  1548. {
  1549. m_childEntityIdOrder.resize(index);
  1550. }
  1551. }
  1552. for (auto& elementChanged : elementsChanged)
  1553. {
  1554. AZ::u64 index = elementChanged.first;
  1555. if (index < m_childEntityIdOrder.size())
  1556. {
  1557. m_childEntityIdOrder[index].m_entityId = elementChanged.second;
  1558. }
  1559. else
  1560. {
  1561. // index is off the end of m_childEntityIdOrder, this can happen because
  1562. // elements could be been removed from the slice. But since this override has changed
  1563. // the entityId we do not want to remove it. So add at end.
  1564. m_childEntityIdOrder.push_back({elementChanged.second, m_childEntityIdOrder.size()});
  1565. }
  1566. }
  1567. // sort the added elements by index
  1568. AZStd::sort(elementsAdded.begin(), elementsAdded.end());
  1569. for (auto& elementAdded : elementsAdded)
  1570. {
  1571. // elements could have been added or removed in the slice so we don't require that there must be an element 3
  1572. // to add element 4, if not we just add it at the end.
  1573. m_childEntityIdOrder.push_back({elementAdded.second, m_childEntityIdOrder.size()});
  1574. }
  1575. }
  1576. // regardless of whether the old m_children was in the patch we always sort m_childEntityIdOrder and reassign sort indices after
  1577. // patching to maintain a consecutive set of sort indices
  1578. // This will sort all the entity order entries by sort index (primary) and entity id (secondary) which should never result in any collisions
  1579. // This is used since slice data patching may create duplicate entries for the same sort index, missing indices and the like.
  1580. // It should never result in multiple entity id entries since the serialization of this data uses a persistent id which is the entity id
  1581. int numChildren = static_cast<int>(m_childEntityIdOrder.size());
  1582. if (numChildren > 0)
  1583. {
  1584. AZStd::sort(m_childEntityIdOrder.begin(), m_childEntityIdOrder.end());
  1585. ResetChildEntityIdSortOrders();
  1586. }
  1587. }
  1588. ////////////////////////////////////////////////////////////////////////////////////////////////////
  1589. void UiElementComponent::ResetChildEntityIdSortOrders()
  1590. {
  1591. // Set the sortIndex on each child to match the order in the vector
  1592. for (AZ::u64 childIndex = 0; childIndex < m_childEntityIdOrder.size(); ++childIndex)
  1593. {
  1594. m_childEntityIdOrder[childIndex].m_sortIndex = childIndex;
  1595. }
  1596. }
  1597. ////////////////////////////////////////////////////////////////////////////////////////////////////
  1598. void UiElementComponent::PrepareElementForDestroy()
  1599. {
  1600. // destroy child elements, this is complicated by the fact that the child elements
  1601. // will attempt to remove themselves from the m_childEntityIdOrder list in their DestroyElement method.
  1602. // But, if the entities are not initialized yet the child parent pointer will be null.
  1603. // So the child may or may not remove itself from the list.
  1604. // So make a local copy of the list and iterate on that
  1605. if (AreChildPointersValid())
  1606. {
  1607. auto childElementComponents = m_childElementComponents;
  1608. for (auto child : childElementComponents)
  1609. {
  1610. // destroy the child
  1611. child->DestroyElement();
  1612. }
  1613. }
  1614. else
  1615. {
  1616. auto children = m_childEntityIdOrder; // need a copy
  1617. for (auto& child : children)
  1618. {
  1619. // destroy the child
  1620. UiElementBus::Event(child.m_entityId, &UiElementBus::Events::DestroyElement);
  1621. }
  1622. }
  1623. // remove this element from parent
  1624. if (m_parent)
  1625. {
  1626. GetParentElementComponent()->RemoveChild(GetEntity());
  1627. }
  1628. // Notify listeners that the element is being destroyed
  1629. UiElementNotificationBus::Event(GetEntityId(), &UiElementNotificationBus::Events::OnUiElementBeingDestroyed);
  1630. }
  1631. ////////////////////////////////////////////////////////////////////////////////////////////////////
  1632. // PRIVATE STATIC MEMBER FUNCTIONS
  1633. ////////////////////////////////////////////////////////////////////////////////////////////////////
  1634. ////////////////////////////////////////////////////////////////////////////////////////////////////
  1635. bool UiElementComponent::VersionConverter(AZ::SerializeContext& context,
  1636. AZ::SerializeContext::DataElementNode& classElement)
  1637. {
  1638. // conversion from version 1 to 2:
  1639. if (classElement.GetVersion() < 2)
  1640. {
  1641. // No need to actually convert anything because the CanvasFileObject takes care of it
  1642. // But it makes sense to bump the version number because m_children is now a container
  1643. // of EntityId rather than Entity*
  1644. }
  1645. // conversion from version 2 to 3:
  1646. // m_children replaced with m_childEntityIdOrder
  1647. // NOTE: We do not go through here if version is 1 since m_children will be an array of Entity*
  1648. // rather than EntityId. That complex conversion is handled in the recursive function
  1649. // MoveEntityAndDescendantsToListAndReplaceWithEntityId
  1650. if (classElement.GetVersion() == 2)
  1651. {
  1652. // Version 3 added the persistent member m_childEntityIdOrder with replaces m_children
  1653. // Find the "Children" element that we will be replacing.
  1654. int childrenIndex = classElement.FindElement(AZ_CRC("Children"));
  1655. if (childrenIndex != -1)
  1656. {
  1657. AZ::SerializeContext::DataElementNode& childrenElementNode = classElement.GetSubElement(childrenIndex);
  1658. // add the new "ChildEntityIdOrder" element, this is a container
  1659. int childOrderIndex = classElement.AddElement<ChildEntityIdOrderArray>(context, "ChildEntityIdOrder");
  1660. AZ::SerializeContext::DataElementNode& childOrderElementNode = classElement.GetSubElement(childOrderIndex);
  1661. int numChildren = childrenElementNode.GetNumSubElements();
  1662. // for each EntityId in the Children container create a ChildEntityIdOrderEntry in the ChildEntityIdOrder container
  1663. for (int childIndex = 0; childIndex < numChildren; ++childIndex)
  1664. {
  1665. AZ::SerializeContext::DataElementNode& childElementNode = childrenElementNode.GetSubElement(childIndex);
  1666. // add the entry in the container (or type ChildEntityIdOrderEntry which is a struct of EntityId and u64)
  1667. int childOrderEntryIndex = childOrderElementNode.AddElement<ChildEntityIdOrderEntry>(context, "element");
  1668. AZ::SerializeContext::DataElementNode& childOrderEntryElementNode = childOrderElementNode.GetSubElement(childOrderEntryIndex);
  1669. // copy the EntityId node from the Children container and change its name
  1670. int childOrderEntryEntityIdIndex = childOrderEntryElementNode.AddElement(childElementNode);
  1671. AZ::SerializeContext::DataElementNode& childOrderEntryEntityIdElementNode = childOrderEntryElementNode.GetSubElement(childOrderEntryEntityIdIndex);
  1672. childOrderEntryEntityIdElementNode.SetName("ChildEntityId");
  1673. // add the the sort index - which is just the position in the container when we are converting old data.
  1674. AZ::u64 sortIndex = childIndex;
  1675. childOrderEntryElementNode.AddElementWithData(context, "SortIndex", sortIndex);
  1676. }
  1677. // remove the old m_children persistent member
  1678. classElement.RemoveElementByName(AZ_CRC("Children"));
  1679. }
  1680. }
  1681. return true;
  1682. }
  1683. ////////////////////////////////////////////////////////////////////////////////////////////////////
  1684. void UiElementComponent::DestroyElementEntity(AZ::EntityId entityId)
  1685. {
  1686. AzFramework::EntityContextId contextId = AzFramework::EntityContextId::CreateNull();
  1687. AzFramework::EntityIdContextQueryBus::EventResult(contextId, entityId, &AzFramework::EntityIdContextQueryBus::Events::GetOwningContextId);
  1688. UiEntityContextRequestBus::Event(contextId, &UiEntityContextRequestBus::Events::DestroyUiEntity, entityId);
  1689. }