ImGuiAssetBrowser.h 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #pragma once
  9. #include <Utils/Utils.h>
  10. #include <Utils/ImGuiMessageBox.h>
  11. #include <AzFramework/Asset/AssetCatalogBus.h>
  12. namespace AtomSampleViewer
  13. {
  14. //! Provides a pair of list boxes for browsing and selecting assets.
  15. //! The first list box is for a collection of all 'available' assets and
  16. //! the second is a list of 'pinned' assets. The client code provides the
  17. //! collection of available assets using PopulateAssets(), and can query
  18. //! the browser for the available, pinned, and selected assets.
  19. //!
  20. //! The state of the UI is stored in a local cache file so the layout
  21. //! and pinned asset list will be preserved between runs.
  22. //!
  23. //! Note, this has nothing to do with the AzToolsFramework::AssetBrowser;
  24. //! it's just a very simple way to expose a pick from a list of assets in ImGui.
  25. class ImGuiAssetBrowser
  26. : public AzFramework::AssetCatalogEventBus::Handler
  27. {
  28. public:
  29. using AssetList = AZStd::vector<Utils::AssetEntry>;
  30. struct WidgetSettings
  31. {
  32. struct Labels
  33. {
  34. const char* m_root = "Assets";
  35. const char* m_assetList = "Available";
  36. const char* m_pinnedAssetList = "Pinned";
  37. const char* m_pinButton = "Pin";
  38. const char* m_unpinButton = "Unpin";
  39. } m_labels;
  40. };
  41. using AssetFilterCallback = AZStd::function<bool(const AZ::Data::AssetInfo& assetInfo)>;
  42. static void Reflect(AZ::ReflectContext* context);
  43. void Activate();
  44. void Deactivate();
  45. //! @param configFilePath - Path to a local json file for maintaining state between runs. Should start with "@user@/"
  46. explicit ImGuiAssetBrowser(AZStd::string_view configFilePath);
  47. //! Set a callback function that will be used to filter which assets should be included in the displayed list.
  48. //! @param shouldInclude - return true for any asset that should be included in the list
  49. void SetFilter(AssetFilterCallback shouldInclude);
  50. //! Returns whether a config file was loaded. See LoadConfigFile()
  51. bool IsConfigFileLoaded() const;
  52. //! Sets the default list of pinned assets, which will be applied if the user clicks "Reset to Defaults".
  53. //! @param assetPaths - A list of paths to asset files in the asset cache.
  54. //! @param applyNow - Calls SetPinnedAssets with this list too
  55. void SetDefaultPinnedAssets(const AZStd::vector<AZStd::string>& assetPaths, bool applyNow = false);
  56. //! Replaces the list of pinned assets
  57. //! @param assetPaths - A list of paths to asset files in the asset cache
  58. void SetPinnedAssets(const AZStd::vector<AZStd::string>& assetPaths);
  59. //! Resets the pin list to the set of default assets. See SetDefaultPinnedAssets().
  60. void ResetPinnedAssetsToDefault();
  61. //! Returns the list of all available assets, shown in the first box
  62. const AssetList& GetAssets() const;
  63. //! Returns the list of all pinned assets, which is a subset of GetAssets(), shown in the second box
  64. const AssetList& GetPinnedAssets() const;
  65. //! Set which of the available assets is selected
  66. void SelectAsset(int32_t assetIndex);
  67. //! Returns the index of the selected asset, or -1 if none is selected
  68. int32_t GetSelectedAssetIndex() const;
  69. //! Returns the AssetId of the selected asset. May be null if there is no selection, or there was an error loading the selected asset.
  70. AZ::Data::AssetId GetSelectedAssetId() const;
  71. //! Returns an Asset<> reference of the selected asset. May be null if there is no selection, or there was an error loading the selected asset.
  72. template<typename AssetDataT>
  73. AZ::Data::Asset<AssetDataT> GetSelectedAsset() const;
  74. //! Returns the path of the selected asset. May be empty if there is no selection, or there was an error loading the selected asset.
  75. AZStd::string GetSelectedAssetPath() const;
  76. //! Returns the index of the previously selected asset, or -1 if none was selected
  77. int32_t GetPrevSelectedAssetIndex() const;
  78. //! Returns the AssetId of the previously selected asset. May be null if there was no selection, or there was an error loading the selected asset.
  79. AZ::Data::AssetId GetPrevSelectedAssetId() const;
  80. //! Draw the ImGui
  81. //! @return true if the asset selection changed
  82. bool Tick(const WidgetSettings& widgetSettings);
  83. //! Force a UI refresh on the next Tick().
  84. void SetNeedsRefresh() { m_needsRefresh = true; }
  85. private:
  86. struct ConfigFile final
  87. {
  88. AZ_TYPE_INFO(ConfigFile, "{42BA95D0-083E-49BD-97B0-5C67A4D2142B}");
  89. AZ_CLASS_ALLOCATOR(ConfigFile, AZ::SystemAllocator, 0);
  90. static void Reflect(AZ::ReflectContext* context);
  91. // We only store paths in the pinned-list because they may change if changes
  92. // are made to the asset builders. This is uncommon for regular users
  93. // but as this may be a more common case for developing and debugging
  94. // Atom it is worth handling.
  95. AZStd::vector<AZStd::string> m_pinnedAssetPaths;
  96. bool m_expandRoot = true;
  97. bool m_expandAvailableList = true;
  98. bool m_expandPinnedList = true;
  99. };
  100. //! Attempts to load the saved widget state from the local cache file.
  101. //! @return true if successfully loaded
  102. bool LoadConfigFile();
  103. void PopulateAssets(AZStd::function<bool(const AZ::Data::AssetInfo& assetInfo)> shouldInclude);
  104. // AzFramework::AssetCatalogEventBus::Handler overrides...
  105. void OnCatalogAssetAdded(const AZ::Data::AssetId& assetId) override;
  106. void OnCatalogAssetRemoved(const AZ::Data::AssetId& assetId, const AZ::Data::AssetInfo& assetInfo) override;
  107. void OnCatalogChanged(const AZ::Data::AssetId& assetId);
  108. void UpdateConfigFilePins();
  109. void SaveConfigFile();
  110. AZStd::string m_configFilePath;
  111. ConfigFile m_configFile;
  112. bool m_isConfigFileLoaded = false;
  113. AssetFilterCallback m_includedAssetFilter;
  114. bool m_needsRefresh = true;
  115. AZStd::vector<AZStd::string> m_defaultPinnedAssetPaths;
  116. ImGuiMessageBox m_confirmClearPinList;
  117. AssetList m_assets;
  118. AssetList m_pinnedAssets;
  119. int32_t m_prevSelectedAssetIndex = -1;
  120. int32_t m_selectedAssetIndex = -1;
  121. int32_t m_selectedPinnedAssetIndex = -1;
  122. };
  123. template<typename AssetDataT>
  124. AZ::Data::Asset<AssetDataT> ImGuiAssetBrowser::GetSelectedAsset() const
  125. {
  126. if (GetSelectedAssetId().IsValid())
  127. {
  128. return AZ::Data::Asset<AssetDataT>{GetSelectedAssetId(), azrtti_typeid<AssetDataT>(), GetSelectedAssetPath()};
  129. }
  130. else
  131. {
  132. return AZ::Data::Asset<AssetDataT>{};
  133. }
  134. }
  135. } // namespace AtomSampleViewer