UiElementComponent.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  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. #pragma once
  9. #include <LyShine/Bus/UiElementBus.h>
  10. #include <LyShine/Bus/UiEditorBus.h>
  11. #include <AzCore/Component/Component.h>
  12. #include <AzCore/Component/EntityBus.h>
  13. #include <AzCore/Slice/SliceBus.h>
  14. #include <AzCore/std/containers/vector.h>
  15. #include "UiSerialize.h"
  16. #include <LyShine/UiComponentTypes.h>
  17. #include <AzCore/std/containers/intrusive_slist.h>
  18. class UiCanvasComponent;
  19. class UiTransform2dComponent;
  20. class UiRenderInterface;
  21. class UiRenderControlInterface;
  22. ////////////////////////////////////////////////////////////////////////////////////////////////////
  23. class UiElementComponent
  24. : public AZ::Component
  25. , public UiElementBus::Handler
  26. , public UiEditorBus::Handler
  27. , public AZ::SliceEntityHierarchyRequestBus::Handler
  28. , public AZ::EntityBus::Handler
  29. , public AZStd::intrusive_slist_node<UiElementComponent>
  30. {
  31. friend class UiCanvasComponent;
  32. public: // types
  33. // used to map old EntityId's to new EntityId's when generating new ids for a paste or prefab
  34. typedef LyShine::EntityIdMap EntityIdMap;
  35. public: // member functions
  36. AZ_COMPONENT(UiElementComponent, LyShine::UiElementComponentUuid, AZ::Component, AZ::SliceEntityHierarchyInterface);
  37. //! Construct an uninitialized element component
  38. UiElementComponent();
  39. ~UiElementComponent() override;
  40. // UiElementInterface
  41. void RenderElement(LyShine::IRenderGraph* renderGraph, bool isInGame) override;
  42. LyShine::ElementId GetElementId() override;
  43. LyShine::NameType GetName() override;
  44. AZ::EntityId GetCanvasEntityId() override;
  45. AZ::Entity* GetParent() override;
  46. AZ::EntityId GetParentEntityId() override;
  47. int GetNumChildElements() override;
  48. AZ::Entity* GetChildElement(int index) override;
  49. AZ::EntityId GetChildEntityId(int index) override;
  50. UiElementInterface* GetChildElementInterface(int index) override;
  51. int GetIndexOfChild(const AZ::Entity* child) override;
  52. int GetIndexOfChildByEntityId(AZ::EntityId childId) override;
  53. LyShine::EntityArray GetChildElements() override;
  54. AZStd::vector<AZ::EntityId> GetChildEntityIds() override;
  55. AZ::Entity* CreateChildElement(const LyShine::NameType& name) override;
  56. void DestroyElement() override;
  57. void DestroyElementOnFrameEnd() override;
  58. void Reparent(AZ::Entity* newParent, AZ::Entity* insertBefore = nullptr) override;
  59. void ReparentByEntityId(AZ::EntityId newParent, AZ::EntityId insertBefore) override;
  60. void AddToParentAtIndex(AZ::Entity* newParent, int index = -1) override;
  61. void RemoveFromParent() override;
  62. AZ::Entity* FindFrontmostChildContainingPoint(AZ::Vector2 point, bool isInGame) override;
  63. LyShine::EntityArray FindAllChildrenIntersectingRect(const AZ::Vector2& bound0, const AZ::Vector2& bound1, bool isInGame) override;
  64. AZ::EntityId FindInteractableToHandleEvent(AZ::Vector2 point) override;
  65. AZ::EntityId FindParentInteractableSupportingDrag(AZ::Vector2 point) override;
  66. AZ::Entity* FindChildByName(const LyShine::NameType& name) override;
  67. AZ::Entity* FindDescendantByName(const LyShine::NameType& name) override;
  68. AZ::EntityId FindChildEntityIdByName(const LyShine::NameType& name) override;
  69. AZ::EntityId FindDescendantEntityIdByName(const LyShine::NameType& name) override;
  70. AZ::Entity* FindChildByEntityId(AZ::EntityId id) override;
  71. AZ::Entity* FindDescendantById(LyShine::ElementId id) override;
  72. void FindDescendantElements(AZStd::function<bool(const AZ::Entity*)> predicate, LyShine::EntityArray& result) override;
  73. void CallOnDescendantElements(AZStd::function<void(const AZ::EntityId)> callFunction) override;
  74. bool IsAncestor(AZ::EntityId id) override;
  75. bool IsEnabled() override;
  76. void SetIsEnabled(bool isEnabled) override;
  77. bool GetAreElementAndAncestorsEnabled() override;
  78. bool IsRenderEnabled() override;
  79. void SetIsRenderEnabled(bool isRenderEnabled) override;
  80. // ~UiElementInterface
  81. // UiEditorInterface
  82. //! The UiElementComponent implements the editor interface in order to store the state with the element on save
  83. bool GetIsVisible() override;
  84. void SetIsVisible(bool isVisible) override;
  85. bool GetIsSelectable() override;
  86. void SetIsSelectable(bool isSelectable) override;
  87. bool GetIsSelected() override;
  88. void SetIsSelected(bool isSelected) override;
  89. bool GetIsExpanded() override;
  90. void SetIsExpanded(bool isExpanded) override;
  91. bool AreAllAncestorsVisible() override;
  92. // ~UiEditorInterface
  93. // EntityEvents
  94. void OnEntityActivated(const AZ::EntityId&) override;
  95. void OnEntityDeactivated(const AZ::EntityId&) override;
  96. // ~EntityEvents
  97. void AddChild(AZ::Entity* child, AZ::Entity* insertBefore = nullptr);
  98. void RemoveChild(AZ::Entity* child);
  99. void RemoveChild(AZ::EntityId child);
  100. //! Only to be used by UiCanvasComponent when creating the root element
  101. void SetCanvas(UiCanvasComponent* canvas, LyShine::ElementId elementId);
  102. //! Only to be used by UiCanvasComponent when loading, cloning etc
  103. bool FixupPostLoad(AZ::Entity* entity, UiCanvasComponent* canvas, AZ::Entity* parent, bool makeNewElementIds);
  104. //! Get the cached UiTransform2dComponent pointer (for optimization)
  105. UiTransform2dComponent* GetTransform2dComponent() const;
  106. //! Get the cached UiElementComponent pointer for the parent (for optimization)
  107. UiElementComponent* GetParentElementComponent() const;
  108. //! Get the cached UiElementComponent pointer for the child (for optimization)
  109. UiElementComponent* GetChildElementComponent(int index) const;
  110. //! Get the cached UiCanvasComponent pointer for the canvas this element belongs to (for optimization)
  111. UiCanvasComponent* GetCanvasComponent() const;
  112. // Used to check that FixupPostLoad has been called
  113. bool IsFullyInitialized() const;
  114. // Used to check that cached child pointers are setup
  115. bool AreChildPointersValid() const;
  116. // SliceEntityHierarchyRequestBus
  117. AZ::EntityId GetSliceEntityParentId() override;
  118. AZStd::vector<AZ::EntityId> GetSliceEntityChildren() override;
  119. // ~SliceEntityHierarchyRequestBus
  120. public: // static member functions
  121. static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
  122. {
  123. provided.push_back(AZ_CRC_CE("UiElementService"));
  124. }
  125. static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
  126. {
  127. incompatible.push_back(AZ_CRC_CE("UiElementService"));
  128. }
  129. static void GetRequiredServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& required)
  130. {
  131. }
  132. static void Reflect(AZ::ReflectContext* context);
  133. static void Initialize();
  134. //! Helper function used during conversion of old format canvas files. Called from
  135. //! UiCanvasFileObject::VersionConverter and PrefabFileObject::VersionConverter.
  136. //! In the old format child entities were referenced by Entity* rather than EntityId so each entity
  137. //! had all of its children nested under it in the file. In the newer format, that was introduced when
  138. //! slice support was added, the entities are owned by the root slice and referenced by entity id.
  139. //! An index of -1 is used when this is called on the root element of the canvas, otherwise index
  140. //! is the index of the child entity withing the children container.
  141. static bool MoveEntityAndDescendantsToListAndReplaceWithEntityId(AZ::SerializeContext& context,
  142. AZ::SerializeContext::DataElementNode& elementNode,
  143. int index,
  144. AZStd::vector<AZ::SerializeContext::DataElementNode>& entities);
  145. protected: // member functions
  146. // AZ::Component
  147. void Activate() override;
  148. void Deactivate() override;
  149. // ~AZ::Component
  150. private: // member functions
  151. //! Send out notifications to elements whose "effective" enabled state has changed
  152. void DoRecursiveEnabledNotification(bool newIsEnabledValue);
  153. private: //types
  154. //! ChildOrderSerializationEvents intercepts the serialization events for patching.
  155. //! This allows us to do some fixup after patching is done on a UiElementComponent.
  156. class ChildOrderSerializationEvents
  157. : public AZ::SerializeContext::IEventHandler
  158. {
  159. //! Called right after we finish writing data to the instance pointed at by classPtr.
  160. void OnPatchEnd(void* classPtr, const AZ::DataPatchNodeInfo& patchInfo) override
  161. {
  162. UiElementComponent* component = reinterpret_cast<UiElementComponent*>(classPtr);
  163. component->OnPatchEnd(patchInfo);
  164. }
  165. };
  166. //! ChildEntityIdOrderEntry stores the entity id and the sort index (which is the absolute sort index relative to
  167. //! the other entries, 0 is the first, 1 is the second, so on). We serialize out the order data in this fashion
  168. //! because the slice data patching system will traditionally use the vector index to know what data goes where.
  169. //! In the case of this data, it does not make sense to data patch by vector index since the underlying data may
  170. //! have changed and the data patch will create duplicate or incorrect data. The slice data patch system has the
  171. //! concept of a "Persistent ID" which can be used instead such that data patches will try to match persistent
  172. //! ids which can be identified regardless of vector index. In this way, our vector order no longer matters and
  173. //! the EntityId is now the identifier which the data patcher will use to update the sort index.
  174. struct ChildEntityIdOrderEntry
  175. {
  176. AZ_TYPE_INFO(ChildEntityIdOrderEntry, "{D6F3CC55-6C7C-4D64-818F-FA3378EC8DA2}");
  177. AZ::EntityId m_entityId;
  178. AZ::u64 m_sortIndex;
  179. bool operator==(const ChildEntityIdOrderEntry& rhs) const
  180. {
  181. return m_entityId == rhs.m_entityId && m_sortIndex == rhs.m_sortIndex;
  182. }
  183. bool operator!=(const ChildEntityIdOrderEntry& rhs) const
  184. {
  185. return m_entityId != rhs.m_entityId || m_sortIndex != rhs.m_sortIndex;
  186. }
  187. bool operator<(const ChildEntityIdOrderEntry& rhs) const
  188. {
  189. return m_sortIndex < rhs.m_sortIndex || (m_sortIndex == rhs.m_sortIndex && m_entityId < rhs.m_entityId);
  190. }
  191. };
  192. using ChildEntityIdOrderArray = AZStd::vector<ChildEntityIdOrderEntry>;
  193. private: // member functions
  194. // Display a warning that the component is not yet fully initialized
  195. void EmitNotInitializedWarning() const;
  196. // helper function for setting the multiple parent reference that we store
  197. void SetParentReferences(AZ::Entity* parent, UiElementComponent* parentElementComponent);
  198. //! Ensures m_childEntityIdOrder is updated for any data patches to the old m_children
  199. void OnPatchEnd(const AZ::DataPatchNodeInfo& patchInfo);
  200. //! Recalculate the sort indices in m_childEntityIdOrder to match the order in the vector
  201. void ResetChildEntityIdSortOrders();
  202. //! Destroys children of UiElement, removes UiElement from parent, and sends OnUiElementBeingDestroyed
  203. void PrepareElementForDestroy();
  204. private: // static member functions
  205. static bool VersionConverter(AZ::SerializeContext& context,
  206. AZ::SerializeContext::DataElementNode& classElement);
  207. //! Destroy UI element entity
  208. static void DestroyElementEntity(AZ::EntityId entityId);
  209. private: // data
  210. AZ_DISABLE_COPY_MOVE(UiElementComponent);
  211. LyShine::ElementId m_elementId = 0;
  212. AZ::Entity* m_parent = nullptr;
  213. AZ::EntityId m_parentId; // Stored in order to do error checking when m_parent could have been deleted
  214. UiCanvasComponent* m_canvas = nullptr; // currently we store a pointer to the canvas component rather than an entity ID
  215. //! Pointers directly to components that are cached for performance to avoid ebus use in critical paths
  216. UiElementComponent* m_parentElementComponent = nullptr;
  217. UiTransform2dComponent* m_transformComponent = nullptr;
  218. AZStd::vector<UiElementComponent*> m_childElementComponents;
  219. UiRenderInterface* m_renderInterface = nullptr;
  220. UiRenderControlInterface* m_renderControlInterface = nullptr;
  221. bool m_isEnabled = true;
  222. bool m_isRenderEnabled = true;
  223. // this data is only relevant when running in the editor, it is accessed through UiEditorBus
  224. bool m_isVisibleInEditor = true;
  225. bool m_isSelectableInEditor = true;
  226. bool m_isSelectedInEditor = false;
  227. bool m_isExpandedInEditor = true;
  228. // New children array that uses persistent IDs. Required because slices/datapatches do not handle things well
  229. // for the old m_children because it doesn't use persistent IDs.
  230. // Note: once loaded and patched this vector is always in the correct order and the sort indices start at zero
  231. // and are contiguous. OnPatchEnd enforces this after any patching.
  232. ChildEntityIdOrderArray m_childEntityIdOrder;
  233. };
  234. ////////////////////////////////////////////////////////////////////////////////////////////////////
  235. // Inline method implementations
  236. ////////////////////////////////////////////////////////////////////////////////////////////////////
  237. inline UiTransform2dComponent* UiElementComponent::GetTransform2dComponent() const
  238. {
  239. AZ_Assert(m_transformComponent, "UiElementComponent: m_transformComponent used when not initialized");
  240. return m_transformComponent;
  241. }
  242. inline UiElementComponent* UiElementComponent::GetParentElementComponent() const
  243. {
  244. AZ_Assert(m_parentElementComponent || !m_parent, "UiElementComponent: m_parentElementComponent used when not initialized");
  245. return m_parentElementComponent;
  246. }
  247. inline UiElementComponent* UiElementComponent::GetChildElementComponent(int index) const
  248. {
  249. AZ_Assert(index >= 0 && index < m_childElementComponents.size(), "UiElementComponent: index to m_childElementComponents out of bounds");
  250. AZ_Assert(m_childElementComponents[index], "UiElementComponent: m_childElementComponents used when not initialized");
  251. return m_childElementComponents[index];
  252. }
  253. inline UiCanvasComponent* UiElementComponent::GetCanvasComponent() const
  254. {
  255. AZ_Assert(m_canvas, "UiElementComponent: m_canvas used when not initialized");
  256. return m_canvas;
  257. }
  258. inline bool UiElementComponent::IsFullyInitialized() const
  259. {
  260. return (m_canvas && m_transformComponent && AreChildPointersValid());
  261. }
  262. inline bool UiElementComponent::AreChildPointersValid() const
  263. {
  264. if (m_childElementComponents.size() == m_childEntityIdOrder.size())
  265. {
  266. return true;
  267. }
  268. AZ_Assert(m_childElementComponents.empty(), "Cached child pointers exist but are a different size to m_children");
  269. return false;
  270. }