text: /*
  * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
  * its licensors.
  *
  * For complete copyright and license terms please see the LICENSE at the root of this
  * distribution (the "License"). All use of this software is governed by the License,
  * or, if provided, by the license below or the license accompanying this file. Do not
  * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  *
  */
  
  #pragma once
  
  #include <AzCore/base.h>
  #include <AzCore/Slice/SliceComponent.h>
  #include <AzCore/UserSettings/UserSettings.h>
  #include <AzCore/Outcome/Outcome.h>
  #include <AzToolsFramework/API/ToolsApplicationAPI.h>
  #include <AzToolsFramework/UI/PropertyEditor/InstanceDataHierarchy.h>
  #include <AzToolsFramework/Slice/SliceTransaction.h>
  
  // Suppresses the following warnings
  // warning C4251: 'QBrush::d': class 'QScopedPointer<QBrushData,QBrushDataPointerDeleter>' needs to have dll-interface to be used by clients of class 'QBrush'
  // warning C4251: 'QGradient::m_stops': class 'QVector<QGradientStop>' needs to have dll-interface to be used by clients of class 'QGradient'
  // warning C4800: 'uint': forcing value to bool 'true' or 'false' (performance warning)
  AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option")
  #include <QString>
  #include <QSize>
  #include <QWidget>
  #include <QLabel>
  #include <QDialog>
  #include <QWidgetAction>
  AZ_POP_DISABLE_WARNING
  
  class QMenu;
  
  namespace AzToolsFramework
  {
      class InstanceDataNode;
  
      namespace SliceUtilities
      {
          using EntityAncestorPair = AZStd::pair<AZ::EntityId, AZStd::shared_ptr<AZ::Entity>>;
          using IdToEntityMapping = AZStd::unordered_map<AZ::EntityId, AZ::Entity*>;
          using IdToInstanceAddressMapping = AZStd::unordered_map<AZ::EntityId, AZ::SliceComponent::SliceInstanceAddress>;
          
          using WillPushEntityCallback = AZStd::function<bool(const AZ::EntityId, const AZ::Data::Asset <AZ::SliceAsset>&)> ;
  
          enum class QuickPushMenuOverrideDisplayCount
          {
              ShowOverrideCountWhenSingle,
              ShowOverrideCountOnlyWhenMultiple
          };
  
          /// Options that can be passed to PupulateQuickPushMenu to affect appearance.
          struct QuickPushMenuOptions
          {
              QuickPushMenuOptions() = default;
              QuickPushMenuOptions(const AZStd::string& headerText, QuickPushMenuOverrideDisplayCount singleOverrideDisplayOption) :
                  m_headerText(headerText),
                  m_singleOverrideDisplayOption(singleOverrideDisplayOption)
              {
              }
  
              AZStd::string m_headerText = "Save Slice Overrides";
              QuickPushMenuOverrideDisplayCount m_singleOverrideDisplayOption = QuickPushMenuOverrideDisplayCount::ShowOverrideCountWhenSingle;
          };
  
          /**
           * Displays slice push UI for the specified set of entities.
           * \param parent - the parent application window
           * \param entities - the list of entity Ids to include in the push request.
           * \param serializeContext - desired serialize context. Specify nullptr to use application's serialize context.
           */
          void PushEntitiesModal(QWidget* parent, const EntityIdList& entities,
                                 AZ::SerializeContext* serializeContext = nullptr);
  
          /**
           * Creates a new slice asset containing the specified entities.
           * If the asset already exists, entities will instead be pushed to the asset to preserve relationships.
           * \param entities - the set of entities to include in the new slice.
           * \param targetDirectory - the preferred directory path.
           * \param inheritSlices - if true, entities already part of slice instances will be added by cascading from their corresponding slices.
           * \param setAsDynamic - if true, the slice is setup as a dynamic slice on creation
           * \param acceptDefaultPath - Whether to prompt the user for a path save location or to proceed with the generated one. Defaults to false
           * \param defaultMoveExternalRefs - Whether to prompt the user on if external entity references found in added entities get added to the created slice or do this automatically. Defaults to false
           * \param defaultGenerateSharedRoot - Whether to generate a shared root if one or more added entities do not share the same root. Defaults to false
           * \param silenceWarningPopups - Disables QT warning popups from being generated, can still rely on the return value for error handling. Defaults to false
           * \return true if slice was created successfully.
           */
          bool MakeNewSlice(const AzToolsFramework::EntityIdSet& entities,
                            const char* targetDirectory, 
                            bool inheritSlices,
                            bool setAsDynamic,
                            bool acceptDefaultPath = false,
                            bool defaultMoveExternalRefs = false,
                            bool defaultGenerateSharedRoot = false,
                            bool silenceWarningPopups = false,
                            AZ::SerializeContext* serializeContext = nullptr);
  
          /**
           * Utility function to gather all referenced entities given a set of entities.
           * This flood searches entity id references, so if you pass in Entity1 that references
           * Entity2, and Entity2 references Entity3, Entity3 is also visited and added to output as
           * a referenced entity.
           * \param entitiesWithReferences - input/output set containing all referenced entities.
           * \param serializeContext - serialize context to use to traverse reflected data.
           */
          void GatherAllReferencedEntities(AzToolsFramework::EntityIdSet& entitiesWithReferences,
                                           AZ::SerializeContext& serializeContext);
  
          /**
           * Utility function to gather all referenced entities given a set of entities and determine
           * if there are references not in original set.
           * This flood searches entity id references, so if you pass in Entity1 that references
           * Entity2, and Entity2 references Entity3, Entity3 is also visited and added to output as
           * a referenced entity.
           * \param entities - input set containing all original entities to search.
           * \param entitiesAndReferencedEntities - input/output set containing all referenced entities.
           * \param hasExternalReferences output true if there are referenced entities not in original entities set
           * \param serializeContext - serialize context to use to traverse reflected data.
           */
          void GatherAllReferencedEntitiesAndCompare(const AzToolsFramework::EntityIdSet& entities,
                                                     AzToolsFramework::EntityIdSet& entitiesAndReferencedEntities,
                                                     bool& hasExternalReferences,
                                                     AZ::SerializeContext& serializeContext);
  
  
          /**
           * Clones a slice-owned entity for the purpose of comparison against a live entity.
           * The key aspect of this utility is the resulting clone has Ids remapped to that of the instance,
           * so entity references don't appear as changes/deltas due to Id remapping during slice instantiation.
           */
          AZStd::unique_ptr<AZ::Entity> CloneSliceEntityForComparison(const AZ::Entity& sourceEntity,
                                                                      const AZ::SliceComponent::SliceInstance& instance,
                                                                      AZ::SerializeContext& serializeContext);
  
          /**
           * Determines if adding instanceToAdd slice to targetInstanceToAddTo slice is safe to do with regard
           * to whether it would create a cyclic asset dependency. Slices cannot contain themselves.
           * \param instanceToAdd - the slice instance wanting to be added
           * \param targetInstanceToAddTo - the slice instance wanting to have instanceToAdd added to
           * \return true if safe to add. false if the slice addition would create a cyclic asset dependency (invalid).
           */
          bool CheckSliceAdditionCyclicDependencySafe(const AZ::SliceComponent::SliceInstanceAddress& instanceToAdd,
                                                      const AZ::SliceComponent::SliceInstanceAddress& targetInstanceToAddTo);
  
  
          /**
           * Push a set of entities to a given slice asset.
           * It is assumed that all provided entities belong to an instance of the provided slice, otherwise AZ::Failure will be returned.
           * \param entityIdList list of live entity Ids whose overrides will be pushed to the slice. Live entities must belong to instances of the specified slice.
           * \param sliceAsset the target slice asset.
           * \param preSaveCallback the callback to use prior to the save to check that it is valid
           * \return AZ::Success if push is completed successfully, otherwise AZ::Failure with an AZStd::string payload.
           */
          AZ::Outcome<void, AZStd::string> PushEntitiesBackToSlice(const AzToolsFramework::EntityIdList& entityIdList,
              const AZ::Data::Asset<AZ::SliceAsset>& sliceAsset, SliceTransaction::PreSaveCallback preSaveCallback);
  
          /**
          * Push a set of entities including addition and subtraction to a given slice asset.
          * \param sliceAsset the target slice asset.
          * \param entitiesToUpdate list of entities whose overrides will be pushed to the slice.
          * \param entitiesToAdd list of entities to add to the slice.
          * \param entitiesToRemove list of entities to remove from the slice.
          * \param preSaveCallback the callback to use prior to the save to check that it is valid
          * \return AZ::Success if push is completed successfully, otherwise AZ::Failure with an AZStd::string payload.
          */
          AZ::Outcome<void, AZStd::string> PushEntitiesIncludingAdditionAndSubtractionBackToSlice(
              const AZ::Data::Asset<AZ::SliceAsset>& sliceAsset,
              const AZStd::unordered_set<AZ::EntityId>& entitiesToUpdate,
              const AZStd::unordered_set<AZ::EntityId>& entitiesToAdd,
              const AZStd::unordered_set<AZ::EntityId>& entitiesToRemove,
              SliceTransaction::PreSaveCallback preSaveCallback,
              SliceTransaction::PostSaveCallback postSaveCallback);
  
          /**
           * Push an individual entity field back to a given slice asset.
           * It is assumed that the provided entity belongs to an instance of the provided slice, otherwise AZ::Failure will be returned.
           * \param entityId live entity Id whose instance of the provided field will be pushed back to the slice.
           * \param sliceAsset the target slice asset.
           * \param fieldNodeAddress InstanceDataHierarchy address of the field to be pushed back to the slice.
           * \param preSaveCallback the callback to use prior to the save to check that it is valid
           * \return AZ::Success if push is completed successfully, otherwise AZ::Failure with an AZStd::string payload.
           */
          AZ::Outcome<void, AZStd::string> PushEntityFieldBackToSlice(AZ::EntityId entityId,
              const AZ::Data::Asset<AZ::SliceAsset>& sliceAsset, const InstanceDataNode::Address& fieldAddress, SliceTransaction::PreSaveCallback preSaveCallback);
  
          /**
           * PreSaveCallback for SliceTransaction::Commits with default world entity rules.
           * Rules include verifying there's a single root entity, making sure root entities have 
           * no translation and clearing out cached world transforms of all entities.
           *
           * If needing custom logic for a PreSaveCallback for world entities, make sure to include this with your own callback:
           *
           * auto myPreSaveCallback = [&](SliceTransaction::TransactionPtr transaction, const char* fullPath, SliceTransaction::SliceAssetPtr& asset) -> SliceTransaction::Result {
           *    // <pre-default-checks custom code here>
           *    auto result = SliceUtilities::SlicePreSaveCallbackForWorldEntities(transaction, fullPath, asset);
           *    if (!result)
           *       return result;
           *    // <post-default-checks custom code here>
           *    return AZ::Success();
           * }
           */
          SliceTransaction::Result SlicePreSaveCallbackForWorldEntities(SliceTransaction::TransactionPtr transaction, const char* fullPath, SliceTransaction::SliceAssetPtr& asset);
  
          void SlicePostPushCallback(SliceTransaction::TransactionPtr transaction, const char* fullSourcePath, const SliceTransaction::SliceAssetPtr& asset);
  
          void SlicePostSaveCallbackForNewSlice(SliceTransaction::TransactionPtr transaction, const char* fullPath, const SliceTransaction::SliceAssetPtr& transactionAsset);
  
          /**
           * Returns true if the entity has no transform parent.
           */
          bool IsRootEntity(const AZ::Entity& entity);
  
          /**
          * \brief Determines whether the provided entity id is the root of a slice or subslice
          * \param id The entity id to check
          */
          bool IsSliceOrSubsliceRootEntity(const AZ::EntityId& id);
  
          /**
           * Retrieves the \ref AZ::Edit::Attributes::SliceFlags assigned to a given data node.
           * \param editData - The specific element data to check for slice flags (can be nullptr)
           * \param classData - The class data to check for slice flags (some flags can cascade from class to all elements, can also be nullptr)
           * return ref AZ::Edit::SliceFlags
           */
          AZ::u32 GetSliceFlags(const AZ::Edit::ElementData* editData, const AZ::Edit::ClassData* classData);
  
          /**
           * Retrieves the \ref AZ::Edit::Attributes::SliceFlags assigned to a given data node.
           * \param node - instance data hierarchy node
           * return ref AZ::Edit::SliceFlags
           */
          AZ::u32 GetNodeSliceFlags(const InstanceDataNode& node);
  
          /**
           * Returns true if the specified node is slice-pushable.
           * \param node instance data node to evaluate.
           * \param isRootEntity (optional) specifies whether the parent entity is a transform root.
           */
          bool IsNodePushable(const InstanceDataNode& node, bool isRootEntity = false);
  
          /**
           * Displays "Save As" QFileDialog to user, generating suggested full slice path based on
           * suggestedName and last place user saved a slice of this type to. Does error checking on
           * user-chosen name like making sure it's ASCII only/it's not taken by slices in other gems
           * \param suggestedName - initial suggested name of the slice
           * \param initialTargetDirectory - default directory to suggest saving in (gets overridden by user settings if present)
           * \param sliceUserSettingsId - CRC id for the SliceUserSettings for a given type of slice, used by "last saved in" logic
           * \param activeWindow - active QWidget for parenting dialog windows to
           * \param outSliceName - [out] name of the slice chosen by user/error checked
           * \param outSliceFilePath - [out] full directory/filename path chosen by user/error checked
           * \return true if valid name chosen, false if not or if cancelled by user
           */
          bool QueryUserForSliceFilename(const AZStd::string& suggestedName, 
                                         const char* initialTargetDirectory,
                                         AZ::u32 sliceUserSettingsId,
                                         QWidget* activeWindow, 
                                         AZStd::string& outSliceName, 
                                         AZStd::string& outSliceFilePath);
  
          /**
           * Populates a QMenu with sub-menus to expose slice override push operations for a provided set of entities.
           * \param outerMenu QMenu to which sub menus will be added.
           * \param inputEntities a set of entities for which quick push options will be determined. Typically callers will pass the selected entity set.
           * \param options optional settings to affect the appearance of the push menu, i.e. title and whether to display a change count if it's singular.
           */
          void PopulateQuickPushMenu(QMenu& outerMenu, const AzToolsFramework::EntityIdList& inputEntities, const QuickPushMenuOptions& options = QuickPushMenuOptions());
  
          /**
           * Populates a QMenu with sub-menus to expose slice override push operations for a specific entity and data field.
           * \param outerMenu QMenu to which sub menus will be added.
           * \param entityId a specific live entity for which the specified field should be pushed.
           * \param fieldAddress address for the specific field to be pushed.
           * \param options optional settings to affect the appearance of the push menu, i.e. title and whether to display a change count if it's singular.
           */
          void PopulateQuickPushMenu(QMenu& outerMenu, AZ::EntityId entityId, const InstanceDataNode::Address& fieldAddress, const QuickPushMenuOptions& options = QuickPushMenuOptions());
  
          /**
          * Get pushable new child entity Ids
          * \param entityIdList input entities
          * \param unpushableEntityIdsPerAsset [out] unpushable new child entity Ids for each potential ancestor
          * \param sliceAncestryMapping [out] mappings from the entity id to the slice ancestry to push to
          * \param newChildEntityIdAncestorPairs [out] Pairs of new child entity Id and the entity ancestor list
          * \param newEntityIds [out] Set of all added newly entityIds, whether pushable or not
          */
          AZStd::unordered_set<AZ::EntityId> GetPushableNewChildEntityIds(
              const AzToolsFramework::EntityIdList& entityIdList,
              AZStd::unordered_map<AZ::Data::AssetId, EntityIdSet>& unpushableEntityIdsPerAsset,
              AZStd::unordered_map<AZ::EntityId, AZ::SliceComponent::EntityAncestorList>& sliceAncestryMapping,
              AZStd::vector<AZStd::pair<AZ::EntityId, AZ::SliceComponent::EntityAncestorList>>& newChildEntityIdAncestorPairs,
              EntityIdSet& newEntityIds);
  
          /**
          * Get unique removed entities
          * \param sliceInstances slice instances which contain select entities
          * \param assetEntityIdtoAssetEntityMappings [out] mappings from asset entity Id to asset entity
          * \param assetEntityIdtoInstanceAddressMappings [out] mappings from asset entity Id to instance address
          */
          AZStd::unordered_set<AZ::EntityId> GetUniqueRemovedEntities(
              const AZStd::vector<AZ::SliceComponent::SliceInstanceAddress>& sliceInstances,
              IdToEntityMapping& assetEntityIdtoAssetEntityMapping,
              IdToInstanceAddressMapping& assetEntityIdtoInstanceAddressMapping);
  
          /** 
           * Defines a callback for PopulateFindSliceMenu. This assists in bridging module boundaries. If the AssetBrowser isn't open when PopulateFindSliceMenu
           * is called, then it should be opened. This can only be done from a Sandbox module. PopulateFindSliceMenu is in AzToolsFramework and not Sandbox so it can
           * share logic with similar menus, like the quick push menu.
           */ 
          typedef void(*SliceSelectedCallback)();
  
          /**
          * Populates two QMenus: one with sub-menu to select slices associated to the passed in entity list in the asset browser and one with a list of parents of the current entity.
          * \param outerMenu The menu used as the parent for the go to slice menu.
          * \param selectedEntity The Entity to use to populate menus with. If this has more than one entry, no menus will be created.
          * \param sliceSelectedCallback Callback for when a slice is selected, run before the asset selection. This allows this functionality to bridge module
          *                              boundaries. SliceUtilities is in AzToolsFramework, but the AssetBrowser largely exists in Sandbox.
          */
          void PopulateSliceSubMenus(QMenu& outerMenu, const AzToolsFramework::EntityIdList& inputEntities, SliceSelectedCallback sliceSelectedCallback, SliceSelectedCallback sliceRelationshipViewCallback);
  
          /**
          * Creates and popluates a menu item associted with the passed in entity.
          * \param selectedEntity The Entity to use to populate the go to slice menu with.
          * \param ancestor slice root ancestor to associate with this item
          * \param menu pointer to menu to add this menu item to.
          * \param indentation amount of whitespace to place in front of this item.
          * \param icon image to display for this menu item.
          * \param tooltip text to display when hovering over item
          * \param sliceAssetId [out] sliceAssetId of the passed in ancestor.
          */
          QWidgetAction* MakeSliceMenuItem(const AZ::EntityId& selectedEntity, const AZ::SliceComponent::Ancestor& ancestor, QMenu* menu, int indentation, const QPixmap icon, QString tooltip, AZ::Data::AssetId& sliceAssetId);
  
          /**
           * Populates a QMenu with a sub-menu to select slices associated to the passed in entity list in the asset browser.
           * \param outerMenu The menu used as the parent for the go to slice menu.
           * \param selectedEntity The Entity to use to populate the go to slice menu with. 
           * \param sliceSelectedCallback Callback for when a slice is selected, run before the asset selection. This allows this functionality to bridge module
           *                              boundaries. SliceUtilities is in AzToolsFramework, but the AssetBrowser largely exists in Sandbox.
           */
          void PopulateFindSliceMenu(QMenu& outerMenu, const AZ::EntityId& selectedEntity, const AZ::SliceComponent::EntityAncestorList& ancestors, SliceSelectedCallback sliceSelectedCallback);
  
          /**
          * Populates a QMenu with a sub-menu to select slices associated to the passed in entity list in the slice relationship view.
          * \param outerMenu The menu used as the parent for the go to slice menu.
          * \param selectedEntity The Entity to use to populate the go to slice menu with.
          * \param sliceSelectedCallback Callback for when a slice is selected, run before the asset selection. This allows this functionality to bridge module
          *                              boundaries. SliceUtilities is in AzToolsFramework, but the AssetBrowser largely exists in Sandbox.
          */
          void PopulateSliceRelationshipViewMenu(QMenu& outerMenu, const AZ::EntityId& selectedEntity, const AZ::SliceComponent::EntityAncestorList& ancestors, SliceSelectedCallback sliceSelectedCallback);
  
          /**
          * Populates a QMenu with a sub-menu to reassign a slices root ancestor to a new base, this operation directly affects the slice asset file
          * \param outerMenu The menu used as the parent for the go to slice menu.
          * \param selectedEntities The entities selected and used to populate the menu
          * \param selectedTransformHierarchyEntities The selected entities and all of their children
          * \param headerText Optional header text
          */
          void PopulateDetachMenu(QMenu& outerMenu, const AzToolsFramework::EntityIdList& selectedEntities, const AzToolsFramework::EntityIdSet& selectedTransformHierarchyEntities, const AZStd::string& headerText = "Detach");
  
          /**
          * Save slice overrides using the hot key.
          * \param inputEntities list of entities whose overrides need to be pushed.
          * \param numEntitiesToAdd [out] number of new entities to add.
          * \param numEntitiesToRemove [out] number of entities to remove.
          * \param numEntitiesToUpdate [out] number of entities to update.
          * \param QuickPushToFirstLevel true if users press the hot key to save overrides to the first level. Otherwise save overrides to the root level.
          */
          bool SaveSlice(
              const AzToolsFramework::EntityIdList& inputEntities,
              int& numEntitiesToAdd,
              int& numEntitiesToRemove,
              int& numEntitiesToUpdate,
              const bool& QuickPushToFirstLevel);
  
          /**
           * Returns true if any of the given entities have slice overrides for their immediate slice ancestor (may be slow on a large group of entities).
           * \param inputEntities The entities to test. If any are not in a slice instance they are ignored.
           */
          bool DoEntitiesHaveOverrides(const AzToolsFramework::EntityIdList& inputEntities);
  
          /**
           * Check to see if a pending reparent request is non-trivial e.g. requires full or partial clones
           *
           * [A]                          | Clones should occur under the following scenarios:
           *  |                           | A ->   |   |   |   |   |   |   |   |   |   |   |   |
           *  |----<B>                    | B ->   |   |   |   |   | F | G | H | I | J | K |   |
           *  |     |                     | C ->   |   |   |   |   |   |   |   |   |   |   |   |
           *  |     |----[C]              | D ->   |   |   |   |   |   |   |   |   |   |   |   |
           *  |     |     |               | E ->   |   |   |   |   |   |   |   |   |   |   |   |
           *  |     |     |---- D         | F ->   |   | C | D | E |   |   |   |   |   | K |   |
           *  |     |                     | G -> A | B | C | D | E |   |   |   |   |   | K | L |
           *  |     |---- E               | H -> A | B | C | D | E | F |   |   |   | J | K | L |
           *  |                           | I -> A | B | C | D | E | F |   |   |   | J | K | L |
           *  |----{F}                    | J ->   |   |   |   |   |   |   |   |   |   |   |   |
           *  |     |                     | K ->   |   | C | D | E | F | G | H | I | J |   |   |
           *  |     |----{G}              | L ->   |   |   |   |   |   |   |   |   |   |   |   |
           *  |           |               |
           *  |           |----<H>        |
           *  |           |               |
           *  |           |----<I>        |
           *  |           |               |--------------------------------
           *  |           |---- J         | Legend: 
           *  |                           | [] - slice root
           *  |----{K}                    | {} - sub slice root
           *  |                           | <> - slice entity
           *  |---- L                     |    - loose entity
           *
           * \param entityId The target entity to reparent
           * \param newParentId The target parent entity
           */
          bool IsReparentNonTrivial(const AZ::EntityId& entityId, const AZ::EntityId& newParentId);
  
          /**
           * Performs the necessary clones on orphaned slice and subslice entities while reparenting existing loose entities and slices.  The source 
           * entities of the clones will be destroyed. 
           * \param entityId The target entity to reparent
           * \param newParentId The target parent entity
           * \return The root ID of the new entity hierarchy after necessary cloning/reparenting
           */
           // LUMBERYARD_DEPRECATED(LY-108703)
          AZ_DEPRECATED(
              AZ::EntityId ReparentNonTrivialEntityHierarchy(const AZ::EntityId& entityId, const AZ::EntityId& newParentId);,
              "ReparentNonTrivialEntityHierarchy is deprecated, please instead use ReparentNonTrivialSliceInstanceHierarchy")
  
          /**
           * Performs the necessary detach operations on orphaned slice and subslice entities while reparenting existing loose entities and slices.
           * \param entityId The target entity to reparent
           * \param newParentId The target parent entity
          */
          void ReparentNonTrivialSliceInstanceHierarchy(const AZ::EntityId& entityId, const AZ::EntityId& newParentId);
  
          /**
          * Reflects slice tools related structures for serialization/editing.
          */
          void Reflect(AZ::ReflectContext* context);
  
          /**
          * Gets the path to the icon used for representing slices.
          */
          QString GetSliceItemIconPath();
  
          /**
          * Gets the path to the icon used for representing modified slices.
          */
          QString GetSliceItemChangedIconPath();
  
          /**
          * Gets the path to the L shape icon.
          */
          QString GetLShapeIconPath();
  
          /**
          * Gets the path to the blue 3d box shape icon.
          */
          QString GetSliceEntityIconPath();
  
          /**
          * Gets the path to the warning icon.
          */
          QString GetWarningIconPath();
  
          /**
          * Gets the height to use for rows that represent slices.
          */
          AZ::u32 GetSliceItemHeight();
  
          /**
          * Gets the size to use for icons representing slices.
          */
          QSize GetSliceItemIconSize();
  
          /**
          * Gets the size of the L shape icon.
          */
          QSize GetLShapeIconSize();
  
          /**
          * Gets the size of the warning icon.
          */
          QSize GetWarningIconSize();
  
          /**
          * Gets the minimum width of the warning label.
          */
          int GetWarningLabelMinimumWidth();
  
          /**
          * Gets the depth to indent slices per level of that slice's hierarchy.
          */
          AZ::u32 GetSliceHierarchyMenuIdentationPerLevel();
  
          /**
          * Gets the font size to make the slice submenu look like the parent menu
          */
          int GetSliceSelectFontSize();
  
          /**
          * Structure for saving/retrieving user settings related to slice workflows.
          */
          class SliceUserSettings
              : public AZ::UserSettings
          {
          public:
              AZ_CLASS_ALLOCATOR(SliceUserSettings, AZ::SystemAllocator, 0);
              AZ_RTTI(SliceUserSettings, "{56EC1A8F-1ADB-4CC7-A3C3-3F462750C31F}", AZ::UserSettings);
  
              AZStd::string m_saveLocation;
              bool m_autoNumber = false; //!< Should the name of the slice file be automatically numbered. e.g SliceName_001.slice vs SliceName.slice.
  
              SliceUserSettings() = default;
  
              static void Reflect(AZ::ReflectContext* context);
          };
  
          class DetachMenuActionWidget
              : public QWidget
          {
          public:
              DetachMenuActionWidget(QWidget* parent, const int& indentation, const AZStd::string& sliceAssetName, const bool& isLastAncestor);
              void enterEvent(QEvent* event) override;
              void leaveEvent(QEvent* event) override;
  
          private:
              void setsliceLabelTextColor(QString color);
  
              QLabel* m_sliceLabel;
              QLabel* m_toLabel;
          };
  
          class MoveToSliceLevelConfirmation
              : public QDialog
          {
          public:
              MoveToSliceLevelConfirmation(QWidget* parent, const AZStd::string& currentSlice, const AZStd::string& destinationSlice);
          };
  
          /// InvalidSliceReferencesWarningResult is used to contain the result
          /// on calls to DisplayInvalidSliceReferencesWarning.
          enum class InvalidSliceReferencesWarningResult
          {
              Save,   ///< The user has chosen continue with the save operation.
              Cancel, ///< The user has chosen to cancel the current operation.
              Details ///< The user has chosen to open the advanced slice push dialog.
          };
  
          /**
          * Displays a message warning the user that the push they are attempting will remove missing invalid references.
          * \param parent The widget to parent the window to.
          * \param invalidSliceCount The number of slices to be saved with invalid references.
          * \param invalidReferenceCount The number of references that will be cleared.
          * \param showDetailsButton True to show a details button to be used to open the advanced slice push window.
          */
          InvalidSliceReferencesWarningResult DisplayInvalidSliceReferencesWarning(
              QWidget* parent,
              size_t invalidSliceCount,
              size_t invalidReferenceCount,
              bool showDetailsButton);
  
          /**
          * Calculates the number of changes in a list of slices to be used in push/revert menu options
          * \param inputEntities List of entities to produce information for
          * \param entitiesToRemove [out] List of entities that have been removed
          * \param numRelevantEntitiesInSlices [out] Number of entities that have changes
          * \param pushableChangesPerAsset [out] List of the number of changes for each entitiy in list
          * \param sliceDisplayOrder [out] List of changes slices in display order
          * \param assetEntityAncestorMap [out] List of ancestors of affected entities
          * \param unpushableEntityIds [out] Set of unpushable entity Ids
          * \return True if there are changes
          */
          bool CountPushableChangesToSlice(const AzToolsFramework::EntityIdList& inputEntities,
              const InstanceDataNode::Address* fieldAddress,
              AZStd::unordered_map<AZ::Data::AssetId, EntityIdSet>& entitiesToAddPerAsset,
              AZStd::unordered_set<AZ::EntityId>& entitiesToRemove,
              size_t& numRelevantEntitiesInSlices,
              AZStd::unordered_map<AZ::Data::AssetId, int>& numPushableChangesPerAsset,
              AZStd::vector<AZ::Data::AssetId>& sliceDisplayOrder,
              AZStd::unordered_map<AZ::Data::AssetId, AZStd::vector<EntityAncestorPair>>& assetEntityAncestorMap,
              AZStd::unordered_map < AZ::Data::AssetId, AZStd::unordered_set<AZ::EntityId>>& pushableEntityIdsPerAsset,
              AZStd::unordered_map<AZ::Data::AssetId, EntityIdSet>&unpushableEntityIdsPerAsset);
  
          /**
          * Returns the file extension (including .) used for slices.
          */
          AZStd::string GetSliceFileExtension();
  
          //! Returns whether or not a given asset is a dynamic slice or not
          bool IsDynamic(const AZ::Data::AssetId& assetId);
  
          //! Toggles if a slice asset is dynamic and re-saves the slice
          void SetIsDynamic(const AZ::Data::AssetId& assetId, bool isDynamic);
  
          /**
          * Creates the right click context menu for slices in the asset browser.
          * \param menu The menu to parent this to.
          * \param fullFilePath The full file path of the slice.
          */
          void CreateSliceAssetContextMenu(QMenu* menu, const AZStd::string& fullFilePath);
  
          /**
          * Retrieves the desired save format for slices.
          * \return The slice save format.
          */
          AZ::DataStream::StreamType GetSliceStreamFormat();
  
          /**
          * Prunes child order array entries that won't be in a pushed slice.
          * \param originalOrderArray Child array with all entities in
          * \param prunedOrderArray [out] Child array after removing unneeded entities.
          * \param targetSlice Slice that the children are being pushed to.
          * \param willPushEntityCallback Callback routine that is called per entity in the array and returns true if the entity will be pushed.
          */
          void RemoveInvalidChildOrderArrayEntries(const AZStd::vector<AZ::EntityId>& originalOrderArray,
              AZStd::vector<AZ::EntityId>& prunedOrderArray,
              const AZ::Data::Asset<AZ::SliceAsset>& targetSlice,
              WillPushEntityCallback willPushEntityCallback);
  
          static const char* splitterColor = "black";
          static const char* detachMenuItemHoverColor = "#4285F4";
          static const char* detachMenuItemDefaultColor = "#ffffff";
          static const char* detailWidgetBackgroundColor = "#303030";
          static const char* unsavableChangesTextColor = "#ff3f3f";
          static const char* conflictedChangesTextColor = "red";
  
      } // namespace SliceUtilities
  
  } // AzToolsFramework
  