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/Code/Framework/AzToolsFramework/AzToolsFramework/Slice/SliceUtilities.h

613 lines
34 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/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 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