#include "Assets.hpp" #include "UI/Localization.hpp" #include "UI/UI.hpp" #include #include #include #include #include #include using namespace std::literals::string_view_literals; namespace fs = std::filesystem; Asset::Asset() { } class AssetList::Private { public: tsl::array_map Assets; tsl::array_map> Cache; int CacheSizeLimit = 0; struct { std::string NewName; NameSelectionError NewNameError = NameSelectionError::Empty; void ShowErrors() const { switch (NewNameError) { case NameSelectionError::None: break; case NameSelectionError::Duplicated: ImGui::ErrorMessage("Duplicate template name"); break; case NameSelectionError::Empty: ImGui::ErrorMessage("Template name cannot be empty"); break; } } bool HasErrors() const { return NewNameError != NameSelectionError::None; } void Validate(const AssetList& self) { if (NewName.empty()) { NewNameError = NameSelectionError::Empty; return; } if (self.FindByName(NewName)) { NewNameError = NameSelectionError::Duplicated; return; } NewNameError = NameSelectionError::None; } } PopupPrivateState; }; AssetList::AssetList() : mPrivate{ std::make_unique() } { } // Write an empty destructor here so std::unique_ptr's destructor can see AssetList::Private's implementation AssetList::~AssetList() { } void AssetList::Reload() { DiscoverFiles([this](SavedAsset asset) -> void { Create(std::move(asset)); }); } const SavedAsset* AssetList::FindByName(std::string_view name) const { auto iter = mPrivate->Assets.find(name); if (iter != mPrivate->Assets.end()) { return &iter.value(); } else { return nullptr; } } const SavedAsset& AssetList::Create(SavedAsset asset) { auto [iter, DISCARD] = mPrivate->Assets.insert(asset.Name, SavedAsset{}); auto& savedAsset = iter.value(); savedAsset = std::move(asset); if (savedAsset.Uuid.is_nil()) { savedAsset.Uuid = uuids::uuid_random_generator{}(); } SaveEmptyInstance(savedAsset); return savedAsset; } std::unique_ptr AssetList::CreateAndLoad(SavedAsset assetIn) { auto& savedAsset = Create(std::move(assetIn)); auto asset = std::unique_ptr(CreateEmptyInstance(savedAsset)); return asset; } std::unique_ptr AssetList::Load(std::string_view name) const { if (auto savedAsset = FindByName(name)) { auto asset = Load(*savedAsset); return asset; } else { return nullptr; } } std::unique_ptr AssetList::Load(const SavedAsset& asset) const { return std::unique_ptr(LoadImpl(asset)); } const SavedAsset* AssetList::Rename(std::string_view oldName, std::string_view newName) { auto iter = mPrivate->Assets.find(oldName); if (iter == mPrivate->Assets.end()) return nullptr; auto info = std::move(iter.value()); info.Name = newName; auto [newIter, DISCARD] = mPrivate->Assets.insert(newName, std::move(info)); mPrivate->Assets.erase(iter); return &newIter.value(); } bool AssetList::Remove(std::string_view name) { auto iter = mPrivate->Assets.find(name); if (iter == mPrivate->Assets.end()) { return false; } auto& asset = iter.value(); fs::remove(RetrievePathFromAsset(asset)); mPrivate->Assets.erase(iter); return true; } int AssetList::GetCacheSizeLimit() const { return mPrivate->CacheSizeLimit; } void AssetList::SetCacheSizeLimit(int limit) { mPrivate->CacheSizeLimit = limit; } void AssetList::DisplayBigIconsList(ListState& state) { // TODO } void AssetList::DisplayDetailsTable(ListState& state) { SetupDetailsTable("AssetDetailsTable"); for (auto& asset : mPrivate->Assets) { DrawDetailsTableRow(state, asset); ImGui::TableNextRow(); } ImGui::EndTable(); } void AssetList::OpenBigIconsPopup() { ImGui::OpenPopup("Manage assets##BigIcons"); } void AssetList::DisplayBigIconsPopup(PopupState& state) { if (ImGui::BeginPopupModal("Manage assets##BigIcons")) { DisplayBigIconsList(state); DisplayPopupControls(state); ImGui::EndPopup(); } } void AssetList::OpenDetailsPopup() { ImGui::OpenPopup("Manage assets##Details"); } void AssetList::DisplayDetailsPopup(PopupState& state) { if (ImGui::BeginPopupModal("Manage assets##Details")) { DisplayBigIconsList(state); DisplayPopupControls(state); ImGui::EndPopup(); } } void AssetList::DiscoverFilesByExtension(const std::function& callback, const fs::path& containerDir, std::string_view extension) const { for (auto entry : fs::directory_iterator(containerDir)) { if (!entry.is_regular_file()) continue; // If the caller provided an extension to match against, and it doesn't equal to current file extension, skip if (!extension.empty() && entry.path().extension() != extension) { continue; } callback(SavedAsset{ .Name = RetrieveNameFromFile(entry.path()), .Uuid = RetrieveUuidFromFile(entry.path()), // TODO load payload }); } } void AssetList::DiscoverFilesByHeader(const std::function& callback, const fs::path& containerDir, const std::function& validater) const { // TODO } void AssetList::DisplayPopupControls(PopupState& state) { auto& ps = mPrivate->PopupPrivateState; auto ls = LocaleStrings::Instance.get(); bool openedDummy = false; if (ImGui::Button(ls->Add.Get())) { ImGui::OpenPopup("Create template"); } if (ImGui::BeginPopupModal("Create template", &openedDummy, ImGuiWindowFlags_AlwaysAutoResize)) { DisplayAssetCreator(state); ImGui::EndPopup(); } ImGui::SameLine(); if (ImGui::Button(ls->Rename.Get(), state.SelectedAsset == nullptr)) { ImGui::OpenPopup("Rename template"); } if (ImGui::BeginPopupModal("Rename template")) { if (ImGui::InputText("New name", &ps.NewName)) { ps.Validate(*this); } if (ImGui::Button(ls->DialogConfirm.Get(), ps.HasErrors())) { ImGui::CloseCurrentPopup(); auto movedAsset = Rename(state.SelectedAsset->Name, ps.NewName); // Update the selected pointer to the new location (we mutated the map, the pointer may be invalid now) state.SelectedAsset = movedAsset; ps = {}; } ImGui::SameLine(); if (ImGui::Button(ls->DialogCancel.Get())) { ImGui::CloseCurrentPopup(); } ps.ShowErrors(); ImGui::EndPopup(); } ImGui::SameLine(); if (ImGui::Button(ls->Delete.Get(), state.SelectedAsset == nullptr)) { ImGui::OpenPopup("Delete confirmation"); } if (ImGui::BeginPopupModal("Delete confirmation")) { if (ImGui::Button(ls->DialogConfirm.Get())) { ImGui::CloseCurrentPopup(); auto& assetName = state.SelectedAsset->Name; Remove(assetName); state.SelectedAsset = nullptr; } ImGui::SameLine(); if (ImGui::Button(ls->DialogCancel.Get())) { ImGui::CloseCurrentPopup(); } ImGui::EndPopup(); } }