You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Gems/LyShine/Code/Source/UiCanvasComponent.h

621 lines
28 KiB
C++

/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/Component/Component.h>
#include <AzCore/Component/EntityBus.h>
#include <AzCore/RTTI/TypeInfo.h>
#include <LyShine/Bus/UiCanvasBus.h>
#include <LyShine/Bus/UiInteractableBus.h>
#include <LyShine/Bus/UiAnimationBus.h>
#include <LyShine/Bus/UiEditorCanvasBus.h>
#include <LyShine/UiEntityContext.h>
#include <LyShine/UiComponentTypes.h>
#include "UiElementComponent.h"
#include "UiSerialize.h"
#include "Animation/UiAnimationSystem.h"
#include "UiLayoutManager.h"
#include "UiNavigationHelpers.h"
#include "RenderGraph.h"
#ifndef _RELEASE
#include "LyShineDebug.h"
#endif
#include "TextureAtlas/TextureAtlas.h"
#include "TextureAtlas/TextureAtlasBus.h"
#include "TextureAtlas/TextureAtlasNotificationBus.h"
#include "RenderToTextureBus.h"
namespace AZ
{
class SerializeContext;
}
struct SDepthTexture;
class CDraw2d;
////////////////////////////////////////////////////////////////////////////////////////////////////
class UiCanvasComponent
: public AZ::Component
, public UiCanvasBus::Handler
, public AZ::EntityBus::Handler
, public UiAnimationBus::Handler
, public UiInteractableActiveNotificationBus::Handler
, public ISystem::CrySystemNotificationBus::Handler
, public IUiAnimationListener
, public UiEditorCanvasBus::Handler
, public UiCanvasComponentImplementationBus::Handler
, public LyShine::RenderToTextureRequestBus::Handler
{
public: // constants
static const AZ::Vector2 s_defaultCanvasSize;
static const AZ::Color s_defaultGuideColor;
public: // member functions
AZ_COMPONENT(UiCanvasComponent, LyShine::UiCanvasComponentUuid, AZ::Component);
//! Constructor, constructed by the LyShine class
UiCanvasComponent();
~UiCanvasComponent() override;
// UiCanvasInterface
const AZStd::string& GetPathname() override;
LyShine::CanvasId GetCanvasId() override;
AZ::u64 GetUniqueCanvasId() override;
int GetDrawOrder() override;
void SetDrawOrder(int drawOrder) override;
bool GetKeepLoadedOnLevelUnload() override;
void SetKeepLoadedOnLevelUnload(bool keepLoaded) override;
void RecomputeChangedLayouts() override;
int GetNumChildElements() override;
AZ::Entity* GetChildElement(int index) override;
AZ::EntityId GetChildElementEntityId(int index) override;
LyShine::EntityArray GetChildElements() override;
AZStd::vector<AZ::EntityId> GetChildElementEntityIds() override;
AZ::Entity* CreateChildElement(const LyShine::NameType& name) override;
AZ::Entity* FindElementById(LyShine::ElementId id) override;
AZ::Entity* FindElementByName(const LyShine::NameType& name) override;
void FindElementsByName(const LyShine::NameType& name, LyShine::EntityArray& result) override;
AZ::EntityId FindElementEntityIdByName(const LyShine::NameType& name) override;
AZ::Entity* FindElementByHierarchicalName(const LyShine::NameType& name) override;
void FindElements(AZStd::function<bool(const AZ::Entity*)> predicate, LyShine::EntityArray& result) override;
AZ::Entity* PickElement(AZ::Vector2 point) override;
LyShine::EntityArray PickElements(const AZ::Vector2& bound0, const AZ::Vector2& bound1) override;
AZ::EntityId FindInteractableToHandleEvent(AZ::Vector2 point) override;
bool SaveToXml(const AZStd::string& assetIdPathname, const AZStd::string& sourceAssetPathname) override;
void FixupCreatedEntities(LyShine::EntityArray topLevelEntities, bool makeUniqueNamesAndIds, AZ::Entity* optionalInsertionPoint) override;
void AddElement(AZ::Entity* element, AZ::Entity* parent, AZ::Entity* insertBefore) override;
void ReinitializeElements() override;
AZStd::string SaveToXmlString() override;
AZStd::string GetUniqueChildName(AZ::EntityId parentEntityId, AZStd::string baseName, const LyShine::EntityArray* includeChildren) override;
AZ::Entity* CloneElement(AZ::Entity* sourceEntity, AZ::Entity* parentEntity) override;
AZ::EntityId CloneElementEntityId(AZ::EntityId sourceEntity, AZ::EntityId parentEntity, AZ::EntityId insertBefore) override;
AZ::Entity* CloneCanvas(const AZ::Vector2& canvasSize) override;
void SetCanvasToViewportMatrix(const AZ::Matrix4x4& matrix) override;
const AZ::Matrix4x4& GetCanvasToViewportMatrix() override;
void GetViewportToCanvasMatrix(AZ::Matrix4x4& matrix) override;
AZ::Vector2 GetCanvasSize() override;
void SetCanvasSize(const AZ::Vector2& canvasSize) override;
void SetTargetCanvasSize(bool isInGame, const AZ::Vector2& targetCanvasSize) override;
AZ::Vector2 GetDeviceScale() override;
bool GetIsPixelAligned() override;
void SetIsPixelAligned(bool isPixelAligned) override;
bool GetIsTextPixelAligned() override;
void SetIsTextPixelAligned(bool isTextPixelAligned) override;
IUiAnimationSystem* GetAnimationSystem() override;
bool GetEnabled() override;
void SetEnabled(bool enabled) override;
bool GetIsRenderToTexture() override;
void SetIsRenderToTexture(bool isRenderToTexture) override;
AZStd::string GetRenderTargetName() override;
void SetRenderTargetName(const AZStd::string& name) override;
bool GetIsPositionalInputSupported() override;
void SetIsPositionalInputSupported(bool isSupported) override;
bool GetIsConsumingAllInputEvents() override;
void SetIsConsumingAllInputEvents(bool isConsuming) override;
bool GetIsMultiTouchSupported() override;
void SetIsMultiTouchSupported(bool isSupported) override;
bool GetIsNavigationSupported() override;
void SetIsNavigationSupported(bool isSupported) override;
float GetNavigationThreshold() override;
void SetNavigationThreshold(float navigationThreshold) override;
AZ::u64 GetNavigationRepeatDelay() override;
void SetNavigationRepeatDelay(AZ::u64 navigationRepeatDelay) override;
AZ::u64 GetNavigationRepeatPeriod() override;
void SetNavigationRepeatPeriod(AZ::u64 navigationRepeatPeriod) override;
AzFramework::LocalUserId GetLocalUserIdInputFilter() override;
void SetLocalUserIdInputFilter(AzFramework::LocalUserId localUserId) override;
bool HandleInputEvent(const AzFramework::InputChannel::Snapshot& inputSnapshot,
const AZ::Vector2* viewportPos = nullptr,
AzFramework::ModifierKeyMask activeModifierKeys = AzFramework::ModifierKeyMask::None) override;
bool HandleTextEvent(const AZStd::string& textUTF8) override;
bool HandleInputPositionalEvent(const AzFramework::InputChannel::Snapshot& inputSnapshot, AZ::Vector2 viewportPos) override;
AZ::Vector2 GetMousePosition() override;
AZ::EntityId GetTooltipDisplayElement() override;
void SetTooltipDisplayElement(AZ::EntityId entityId) override;
void ForceFocusInteractable(AZ::EntityId interactableId) override;
void ForceActiveInteractable(AZ::EntityId interactableId, bool shouldStayActive, AZ::Vector2 point) override;
AZ::EntityId GetHoverInteractable() override;
void ForceHoverInteractable(AZ::EntityId interactableId) override;
void ClearAllInteractables() override;
void ForceEnterInputEventOnInteractable(AZ::EntityId interactableId) override;
// ~UiCanvasInterface
// EntityEvents
void OnEntityDeactivated(const AZ::EntityId& entityId) override;
// ~EntityEvents
// UiAnimationInterface
void StartSequence(const AZStd::string& sequenceName) override;
void PlaySequenceRange(const AZStd::string& sequenceName, float startTime, float endTime) override;
void StopSequence(const AZStd::string& sequenceName) override;
void AbortSequence(const AZStd::string& sequenceName) override;
void PauseSequence(const AZStd::string& sequenceName) override;
void ResumeSequence(const AZStd::string& sequenceName) override;
void ResetSequence(const AZStd::string& sequenceName) override;
float GetSequencePlayingSpeed(const AZStd::string& sequenceName) override;
void SetSequencePlayingSpeed(const AZStd::string& sequenceName, float speed) override;
float GetSequencePlayingTime(const AZStd::string& sequenceName) override;
bool IsSequencePlaying(const AZStd::string& sequenceName) override;
float GetSequenceLength(const AZStd::string& sequenceName) override;
void SetSequenceStopBehavior(IUiAnimationSystem::ESequenceStopBehavior stopBehavior) override;
// ~UiAnimationInterface
// UiInteractableActiveNotifications
void ActiveCancelled() override;
void ActiveChanged(AZ::EntityId m_newActiveInteractable, bool shouldStayActive) override;
// ~UiInteractableActiveNotifications
// ISystem::CrySystemNotifications
void OnPreRender() override;
//ISystem::CrySystemNotifications
// IUiAnimationListener
void OnUiAnimationEvent(EUiAnimationEvent uiAnimationEvent, IUiAnimSequence* pAnimSequence) override;
void OnUiTrackEvent(AZStd::string eventName, AZStd::string valueName, IUiAnimSequence* pAnimSequence) override;
// ~IUiAnimationListener
// UiEditorCanvasInterface
bool GetIsSnapEnabled() override;
void SetIsSnapEnabled(bool enabled) override;
float GetSnapDistance() override;
void SetSnapDistance(float distance) override;
float GetSnapRotationDegrees() override;
void SetSnapRotationDegrees(float degrees) override;
AZStd::vector<float> GetHorizontalGuidePositions() override;
void AddHorizontalGuide(float position) override;
void RemoveHorizontalGuide(int index) override;
void SetHorizontalGuidePosition(int index, float position) override;
AZStd::vector<float> GetVerticalGuidePositions() override;
void AddVerticalGuide(float position) override;
void RemoveVerticalGuide(int index) override;
void SetVerticalGuidePosition(int index, float position) override;
void RemoveAllGuides() override;
AZ::Color GetGuideColor() override;
void SetGuideColor(const AZ::Color& color) override;
bool GetGuidesAreLocked() override;
void SetGuidesAreLocked(bool areLocked) override;
bool CheckForOrphanedElements() override;
void RecoverOrphanedElements() override;
void RemoveOrphanedElements() override;
void UpdateCanvasInEditorViewport(float deltaTime, bool isInGame) override;
void RenderCanvasInEditorViewport(bool isInGame, AZ::Vector2 viewportSize) override;
// ~UiEditorCanvasInterface
// UiCanvasComponentImplementationInterface
void MarkRenderGraphDirty() override;
// ~UiCanvasComponentImplementationInterface
// RenderToTextureRequests
AZ::RHI::AttachmentId UseRenderTarget(const AZ::Name& renderTargetName, AZ::RHI::Size size) override;
void ReleaseRenderTarget(const AZ::RHI::AttachmentId& attachmentId) override;
AZ::Data::Instance<AZ::RPI::AttachmentImage> GetRenderTarget(const AZ::RHI::AttachmentId& attachmentId) override;
// ~RenderToTextureRequests
void UpdateCanvas(float deltaTime, bool isInGame);
void RenderCanvas(bool isInGame, AZ::Vector2 viewportSize, UiRenderer* uiRenderer = nullptr);
AZ::Entity* GetRootElement() const;
LyShine::ElementId GenerateId();
//! Clone this canvas's entity and return the Canvas component
//! (used when it is loaded from in game or for preview mode etc)
UiCanvasComponent* CloneAndInitializeCanvas(UiEntityContext* entityContext, const AZStd::string& assetIdPathname, const AZ::Vector2* canvasSize = nullptr);
//! Deactivate all elements. Used when queuing a canvas up for deletion
void DeactivateElements();
AZ::Vector2 GetTargetCanvasSize();
//! Get the mapping from editor EntityId to game EntityId. This will be empty for canvases loaded for editing
AZ::SliceComponent::EntityIdToEntityIdMap GetEditorToGameEntityIdMap() { return m_editorToGameEntityIdMap; }
void ScheduleElementForTransformRecompute(UiElementComponent* elementComponent);
void UnscheduleElementForTransformRecompute(UiElementComponent* elementComponent);
//! Queue an element to be destroyed at end of frame
void ScheduleElementDestroy(AZ::EntityId entityId);
bool IsRenderGraphDirty() { return m_renderGraph.GetDirtyFlag(); }
void GetRenderTargets(LyShine::AttachmentImagesAndDependencies& attachmentImagesAndDependencies);
#ifndef _RELEASE
struct DebugInfoNumElements
{
int m_numElements;
int m_numEnabledElements;
int m_numRenderElements;
int m_numRenderControlElements;
int m_numImageElements;
int m_numTextElements;
int m_numMaskElements;
int m_numFaderElements;
int m_numInteractableElements;
int m_numUpdateElements;
};
void GetDebugInfoInteractables(AZ::EntityId& activeInteractable, AZ::EntityId& hoverInteractable) const;
void GetDebugInfoNumElements(DebugInfoNumElements& info) const;
void GetDebugInfoRenderGraph(LyShineDebug::DebugInfoRenderGraph& info) const;
void DebugInfoCountChildren(const AZ::EntityId entity, bool parentEnabled, DebugInfoNumElements& info) const;
void DebugReportDrawCalls(AZ::IO::HandleType fileHandle, LyShineDebug::DebugInfoDrawCallReport& reportInfo, void* context) const;
void DebugDisplayElemBounds(CDraw2d* draw2d) const;
void DebugDisplayChildElemBounds(CDraw2d* draw2d, const AZ::EntityId entity) const;
#endif
public: // static member functions
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC("UiCanvasService", 0x2c8e8f87));
}
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC("UiCanvasService", 0x2c8e8f87));
}
static void GetRequiredServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& required)
{
}
static void Reflect(AZ::ReflectContext* context);
// TODO: Move these static functions into a CanvasManager class
static void Initialize();
static void Shutdown();
static UiCanvasComponent* CreateCanvasInternal(UiEntityContext* entityContext, bool forEditor);
static UiCanvasComponent* LoadCanvasInternal(const AZStd::string& pathToOpen, bool forEditor, const AZStd::string& assetIdPathname, UiEntityContext* entityContext,
const AZ::SliceComponent::EntityIdToEntityIdMap* previousRemapTable = nullptr, AZ::EntityId previousCanvasId = AZ::EntityId());
static UiCanvasComponent* FixupReloadedCanvasForEditorInternal(AZ::Entity* newCanvasEntity,
AZ::Entity* rootSliceEntity, UiEntityContext* entityContext,
LyShine::CanvasId existingId, const AZStd::string& existingPathname);
protected: // member functions
// AZ::Component
void Init() override;
void Activate() override;
void Deactivate() override;
// ~AZ::Component
private: // member functions
AZ_DISABLE_COPY_MOVE(UiCanvasComponent);
// Texture Atlas loading
void LoadAtlases();
void UnloadAtlases();
void ReloadAtlases();
// handle events for this canvas
bool HandleHoverInputEvent(AZ::Vector2 point);
bool HandleKeyInputEvent(const AzFramework::InputChannel::Snapshot& inputSnapshot, AzFramework::ModifierKeyMask activeModifierKeys = AzFramework::ModifierKeyMask::None);
bool HandleNavigationInputEvent(UiNavigationHelpers::Command command, const AzFramework::InputChannel::Snapshot& inputSnapshot);
bool HandleEnterInputEvent(UiNavigationHelpers::Command command, const AzFramework::InputChannel::Snapshot& inputSnapshot);
bool HandleBackInputEvent(UiNavigationHelpers::Command command, const AzFramework::InputChannel::Snapshot& inputSnapshot);
// A key was pressed to deactivate the active interactable
bool DeactivateInteractableByKeyInput(const AzFramework::InputChannel::Snapshot& inputSnapshot);
// A key was pressed to transfer hover to the ancestor interactable
bool PassHoverToAncestorByKeyInput(const AzFramework::InputChannel::Snapshot& inputSnapshot);
// Code shared by all positional input events
bool HandlePrimaryPress(AZ::Vector2 point);
bool HandlePrimaryUpdate(AZ::Vector2 point);
bool HandlePrimaryRelease(AZ::Vector2 point);
bool HandleMultiTouchPress(AZ::Vector2 point, int multiTouchIndex);
bool HandleMultiTouchRelease(AZ::Vector2 point, int multiTouchIndex);
bool HandleMultiTouchUpdated(AZ::Vector2 point, int multiTouchIndex);
bool IsInteractableActiveOrPressed(AZ::EntityId interactableId) const;
// Functions to change the hover and active interactables
void SetHoverInteractable(AZ::EntityId interactableId);
void ClearHoverInteractable();
void SetActiveInteractable(AZ::EntityId newActiveInteractable, bool shouldStayActive);
void ClearActiveInteractable();
//! Check if the hover interactable is set to auto-activate, and if so activate it
void CheckHoverInteractableAndAutoActivate(AZ::EntityId prevHoverInteractable = AZ::EntityId(), UiNavigationHelpers::Command command = UiNavigationHelpers::Command::Unknown, bool forceAutoActivate = false);
//! Check if the active interactable has a descendant interactable. If it does,
//! make the descendant the hover interactable and clear the active interactable
void CheckActiveInteractableAndPassHoverToDescendant(AZ::EntityId prevHoverInteractable = AZ::EntityId(), UiNavigationHelpers::Command command = UiNavigationHelpers::Command::Unknown);
//! Find the first interactable ancestor of the specified element
AZ::EntityId FindAncestorInteractable(AZ::EntityId entityId);
//! Get the first hover interactable, defaulting to the one set by the canvas
AZ::EntityId GetFirstHoverInteractable();
//! Find the first interactable to receive focus
AZ::EntityId FindFirstHoverInteractable(AZ::EntityId parentElement = AZ::EntityId());
//! Set the hover interactable on canvas load
void SetFirstHoverInteractable();
//! Due to differences in their serialization systems we need to do some work before save
void PrepareAnimationSystemForCanvasSave();
//! Due to differences in their serialization systems we need to do some work after load
void RestoreAnimationSystemAfterCanvasLoad(bool remapIds, UiElementComponent::EntityIdMap* entityIdMap);
//! Get a list of entity IDs for this element and all its descendant elements
AZStd::vector<AZ::EntityId> GetEntityIdsOfElementAndDescendants(AZ::Entity* entity);
//! Calculate the target canvas size and uniform scale
void SetTargetCanvasSizeAndUniformScale(bool isInGame, AZ::Vector2 canvasSize);
//! Check if an element name is unique
bool IsElementNameUnique(const AZStd::string& elementName, const LyShine::EntityArray& elements);
//! Methods used for controlling the Edit Context (the properties pane)
using EntityComboBoxVec = AZStd::vector< AZStd::pair< AZ::EntityId, AZStd::string > >;
EntityComboBoxVec PopulateNavigableEntityList();
EntityComboBoxVec PopulateTooltipDisplayEntityList();
void OnPixelAlignmentChange();
void OnTextPixelAlignmentChange();
void CreateRenderTarget();
void DestroyRenderTarget();
void RenderCanvasToTexture();
bool SaveCanvasToFile(const AZStd::string& pathname, AZ::DataStream::StreamType streamType);
bool SaveCanvasToStream(AZ::IO::GenericStream& stream, AZ::DataStream::StreamType streamType);
//! Notify elements that their canvas space rect has changed since the last update, and recompute invalid layouts
void SendRectChangeNotificationsAndRecomputeLayouts();
//! Notify elements that their canvas space rect has changed since the last update
void SendRectChangeNotifications();
//! Compute the layout for all elements. Parents are computed first, then children.
//! Called on canvas initialization
void InitializeLayouts();
//! Call InGamePostActivate on children first, then parent
void InGamePostActivateBottomUp(AZ::Entity* entity);
//! Internal function for cloning an element
AZ::Entity* CloneAndAddElementInternal(AZ::Entity* sourceEntity, AZ::Entity* parentEntity, AZ::Entity* insertBeforeEntity);
//! Get any orphaned elements caused by old bugs
void GetOrphanedElements(AZ::SliceComponent::EntityList& orphanedEntities);
void DestroyScheduledElements();
//! Notify LyShine pass that it needs to rebuild its Rtt child passes
void QueueRttPassRebuild();
private: // static member functions
static AZ::u64 CreateUniqueId();
static UiCanvasComponent* FixupPostLoad(AZ::Entity* canvasEntity, AZ::Entity* rootSliceEntity, bool forEditor, UiEntityContext* entityContext,
const AZ::Vector2* canvasSize = nullptr, const AZ::SliceComponent::EntityIdToEntityIdMap* previousRemapTable = nullptr, AZ::EntityId previousCanvasId = AZ::EntityId());
static bool VersionConverter(AZ::SerializeContext& context,
AZ::SerializeContext::DataElementNode& classElement);
private: // types
typedef std::vector<UiCanvasComponent*> CanvasList; //!< Sorted by draw order
private: // data
AZStd::string m_pathname; //! This is an asset ID pathname
AZ::u64 m_uniqueId;
AZ::EntityId m_rootElement;
LyShine::ElementId m_lastElementId;
bool m_isPixelAligned = true; //! if true all visual elements have their vertices snapped to the nearest pixel
bool m_isTextPixelAligned = true; //! if true all text is snapped to the nearest pixel
AZ::EntityId m_firstHoverInteractable;
bool m_isPositionalInputSupported = true;
bool m_isConsumingAllInputEvents = false;
bool m_isMultiTouchSupported = true;
bool m_isNavigationSupported = true;
float m_navigationThreshold = 0.4f;
AZ::u64 m_navigationRepeatDelay = 300;
AZ::u64 m_navigationRepeatPeriod = 150;
AzFramework::LocalUserId m_localUserIdInputFilter = AzFramework::LocalUserIdAny;
AZ::EntityId m_tooltipDisplayElement;
AZ::Matrix4x4 m_canvasToViewportMatrix;
AZ::Matrix4x4 m_viewportToCanvasMatrix;
AZStd::vector <AzFramework::SimpleAssetReference<TextureAtlasNamespace::TextureAtlasAsset>> m_atlasPathNames; //! This is a list of filepaths for TextureAtlases
AZStd::vector<TextureAtlasNamespace::TextureAtlas*> m_atlases;
// In the comments below an "interactable entity" is an entity that is connected to the
// UiInteractableBus
//! The hover interactable is the interactable entity that the mouse cursor is currently over
//! (or is selected by keyboard/controller navigation). The canvas tracks it so that it can tell
//! the hover interactable that it is no longer in hover state when the cursor moves outside its bounds
AZ::EntityId m_hoverInteractable;
//! The active interactable is the interactable entity that the canvas considers "active".
//! The active interactable is initially the interactable that handled the pressed event.
//! An interactable can request to be stay active after the released event by returning
//! "shouldStayActive" from HandlePressed. In this case the active interactable remains
//! the active interactable until another interactable becomes active
//! or until the active interactable itself requests to cancel its active status.
//! If there is an active interactable when a released event is received then it
//! is sent to the active interactable.
//! The active interactable gets sent the mouse/touch position each frame (to support drag).
//! The active interactable gets sent any character input received by the canvas.
AZ::EntityId m_activeInteractable;
//! If this is true the active interactable stays active after the release event
bool m_activeInteractableShouldStayActive;
//! True if the mouse is pressed or the enter key is down and there is an active interactable
bool m_isActiveInteractablePressed;
//! The last mouse position. Used to detect mouse movement
AZ::Vector2 m_lastMousePosition;
//! A map of all interactables that have handled a multi-touch (non-primary) pressed
//! event but that are still waiting to receive the corresponding released event
AZStd::unordered_map<int, AZ::EntityId> m_multiTouchInteractablesByTouchIndex;
struct NavigationStatus
{
AZ::u64 lastNavigationTime;
int navigationCount;
bool allowNavigation;
};
//! The status of navigation in each direction
AZStd::unordered_map<UiNavigationHelpers::Command, NavigationStatus> m_navCommandStatus;
LyShine::CanvasId m_id;
int m_drawOrder;
//! The authored canvas size, in pixels
//
//! While in the editor, this is the resolution that we display the canvas at. While in
//! game, the authored canvas size is used to calculate m_uniformDeviceScale, which is
//! used to apply the "scale to device" feature.
AZ::Vector2 m_canvasSize;
//! The target size of the canvas in pixels
//
//! The resolution that we display the canvas at. While in-game, we assume the canvas
//! occupies the entire screen, so it is set to the viewport size. In the Editor, we
//! set the target size to be the authored canvas size.
AZ::Vector2 m_targetCanvasSize;
//! The scale that will convert from canvasSize to viewportSize.
//! In the editor this is always 1.0f
//! In game it is the closer value to 1.0f of the two values m_viewportSize.x/m_canvasSize.x
//! and m_viewportSize.y/m_canvasSize.y
AZ::Vector2 m_deviceScale;
//! True if this canvas is loaded in game (including for Ctrl-G in Sandbox), false if open in the UI Editor
bool m_isLoadedInGame;
//! This flag allows some UI canvases to stay loaded when transitioning from one level to another
bool m_keepLoadedOnLevelUnload;
//! True (default) if the canvas is visible and updated each frame, false otherwise
bool m_enabled;
//! Each canvas has its own animation system to manage all its animation sequences
UiAnimationSystem m_uiAnimationSystem;
UiSerialize::AnimationData m_serializedAnimationData;
//! If true the canvas is not rendered to the screen but is instead rendered to a texture
bool m_renderToTexture;
//! The user-specified name for the render target taht we render to if m_renderToTexture is true
AZStd::string m_renderTargetName;
//! When rendering to a texture this is the texture ID of the render target
int m_renderTargetHandle = -1;
//! When rendering to a texture this is our depth surface
SDepthTexture* m_renderTargetDepthSurface = nullptr;
//! Each canvas has a layout manager to track and recompute layouts
UiLayoutManager* m_layoutManager = nullptr;
bool m_isSnapEnabled;
float m_snapDistance;
float m_snapRotationDegrees;
//! guides (editor-only)
AZStd::vector<float> m_horizontalGuidePositions;
AZStd::vector<float> m_verticalGuidePositions;
AZ::Color m_guideColor;
bool m_guidesAreLocked;
UiEntityContext* m_entityContext;
AZ::SliceComponent::EntityIdToEntityIdMap m_editorToGameEntityIdMap;
//! This is an optimization to avoid visiting all elements multiple times every frame to see if any of them need recomputing
//! We use an intrusive_slist to avoid any memory allocations and also to cheaply be able to tell if an element is already in list
using ElementComponentSlist = AZStd::intrusive_slist<UiElementComponent, AZStd::slist_base_hook<UiElementComponent>>;
ElementComponentSlist m_elementsNeedingTransformRecompute;
//! Holds elements that are queued up to be deleted at end of frame
AZStd::vector<AZ::EntityId> m_elementsScheduledForDestroy;
private: // static data
//! If true update which element should be the hover interactable based on input position
//! and notify the active interactable of position changes. Set to false when a key event
//! occurs and back to true on mouse/touch activity.
static bool s_handleHoverInputEvents;
//! If true, when handling hover input events, allow clearing the hover interactable if the mouse isn't
//! over any interactables. Set to false when a key event occurs and back to true when handling hover
//! input events and the input position hovers over an interactable.
static bool s_allowClearingHoverInteractableOnHoverInput;
LyShine::RenderGraph m_renderGraph; //!< the render graph for rendering the canvas, can be cached between frames
bool m_isRendering = false;
bool m_renderInEditor = false; //!< indicates whether this canvas will render in the Editor viewport or the Game viewport
//! Map of attachments used by this canvas's elements
AZStd::unordered_map<AZ::RHI::AttachmentId, AZ::Data::Instance<AZ::RPI::AttachmentImage>> m_attachmentImageMap;
};