#pragma once #include #include #include #include #include /// A structure representing a ready-to-be-loaded asset, locating on the disk. struct SavedAsset { std::filesystem::path Path; std::string Name; /// `Path`'s string form, encoded in UTF-8. std::string PathString = Path.string(); }; class Asset { public: Asset(); virtual ~Asset() = default; }; class AssetCategory { public: virtual ~AssetCategory() = default; virtual void DiscoverFiles(const std::function& callback) const = 0; virtual Asset* CreateEmpty(const SavedAsset& diskForm) const = 0; std::unique_ptr CreateEmptyUnique(const SavedAsset& diskForm) const; virtual Asset* Load(const SavedAsset& diskForm) const = 0; std::unique_ptr LoadUnique(const SavedAsset& diskForm) const; /// This should call ImGui::BeginTable() along with other accessories such as setting up the header row. virtual void SetupDetailsTable(const char* tableId) const = 0; virtual void DrawBigIcon(const SavedAsset& asset) const = 0; virtual void DrawDetailsTableRow(const SavedAsset& asset) const = 0; protected: /* Helper loader functions */ static void DiscoverFilesByExtension(const std::function& callback, const std::filesystem::path& containerDir, std::string_view extension); static void DiscoverFilesByHeader(const std::function& callback, const std::filesystem::path& containerDir, const std::function& validater); }; class AssetList { private: const AssetCategory* mLoader; tsl::array_map mAssets; tsl::array_map> mCache; int mCacheSizeLimit = 0; public: AssetList(const AssetCategory& loader); // TODO support file watches void Reload(); const SavedAsset* FindByName(std::string_view name) const; const SavedAsset& Create(SavedAsset asset); std::unique_ptr CreateAndLoad(SavedAsset asset); std::unique_ptr LoadFromDisk(std::string_view name) const; bool Rename(std::string_view oldName, std::string_view newName); bool Remove(std::string_view name); int GetCacheSizeLimit() const; void SetCacheSizeLimit(int limit); struct DrawState { const SavedAsset* SelectedAsset = nullptr; }; void DrawBigIcons(DrawState& state); void DrawDetails(DrawState& state); }; template class TypedAssetList : public AssetList { public: using Asset = TAsset; using AssetType = typename TAsset::CategoryType; public: // Import constructor using AssetList::AssetList; Asset* FindByName(std::string_view name) const { return static_cast(AssetList::FindByName(name)); } std::unique_ptr Create(std::string_view name) { return std::unique_ptr(static_cast(AssetList::Create(name).release())); } std::unique_ptr LoadFromDisk(std::string_view name) const { return std::unique_ptr(static_cast(AssetList::LoadFromDisk(name))); } };