diff options
author | rtk0c <[email protected]> | 2021-06-07 12:19:51 -0700 |
---|---|---|
committer | rtk0c <[email protected]> | 2021-06-07 12:19:51 -0700 |
commit | d7ee2efaca226fc478e3f0c78abdbe86a887f17a (patch) | |
tree | 81670fefb7cdba3c5fa0ab890f7d84e24c194bdb /core | |
parent | a180e1b56025c6b7d81d2e587ad90531d29de44c (diff) |
Complete asset loading/saving and UI management logic
Diffstat (limited to 'core')
-rw-r--r-- | core/src/Model/Assets.cpp | 116 | ||||
-rw-r--r-- | core/src/Model/Assets.hpp | 97 | ||||
-rw-r--r-- | core/src/Model/Project.hpp | 4 | ||||
-rw-r--r-- | core/src/Model/Template/Template.hpp | 19 | ||||
-rw-r--r-- | core/src/Model/Template/Template_Main.cpp | 62 | ||||
-rw-r--r-- | core/src/Model/Template/fwd.hpp | 2 | ||||
-rw-r--r-- | core/src/Model/Workflow/Workflow.hpp | 18 | ||||
-rw-r--r-- | core/src/Model/Workflow/Workflow_Main.cpp | 134 | ||||
-rw-r--r-- | core/src/Model/Workflow/fwd.hpp | 2 | ||||
-rw-r--r-- | core/src/Model/fwd.hpp | 3 | ||||
-rw-r--r-- | core/src/UI/UI_Templates.cpp | 41 | ||||
-rw-r--r-- | core/src/UI/UI_Workflows.cpp | 54 |
12 files changed, 309 insertions, 243 deletions
diff --git a/core/src/Model/Assets.cpp b/core/src/Model/Assets.cpp index e4eee54..a1e9730 100644 --- a/core/src/Model/Assets.cpp +++ b/core/src/Model/Assets.cpp @@ -4,54 +4,16 @@ #include <fstream> #include <utility> +using namespace std::literals::string_view_literals; namespace fs = std::filesystem; Asset::Asset() { } -std::unique_ptr<Asset> AssetCategory::CreateEmptyUnique(const SavedAsset& diskForm) const -{ - return std::unique_ptr<Asset>(CreateEmpty(diskForm)); -} - -std::unique_ptr<Asset> AssetCategory::LoadUnique(const SavedAsset& diskForm) const -{ - return std::unique_ptr<Asset>(Load(diskForm)); -} - -void AssetCategory::DiscoverFilesByExtension(const std::function<void(SavedAsset)>& callback, const std::filesystem::path& containerDir, std::string_view extension) -{ - 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{ - .Path = entry.path(), - .Name = entry.path().stem().string(), - }); - } -} - -void AssetCategory::DiscoverFilesByHeader(const std::function<void(SavedAsset)>& callback, const std::filesystem::__cxx11::path& containerDir, const std::function<bool(std::istream&)>& validater) -{ - // TODO -} - -AssetList::AssetList(const AssetCategory& loader) - : mLoader{ &loader } -{ -} - void AssetList::Reload() { - mLoader->DiscoverFiles([this](SavedAsset asset) -> void { + DiscoverFiles([this](SavedAsset asset) -> void { Create(std::move(asset)); }); } @@ -71,8 +33,12 @@ const SavedAsset& AssetList::Create(SavedAsset asset) auto [iter, DISCARD] = mAssets.insert(asset.Name, SavedAsset{}); auto& savedAsset = iter.value(); - mLoader->CreateEmpty(asset); savedAsset = std::move(asset); + if (savedAsset.Uuid.is_nil()) { + savedAsset.Uuid = uuids::uuid_random_generator{}(); + } + + SaveEmptyInstance(savedAsset); return savedAsset; } @@ -80,24 +46,51 @@ const SavedAsset& AssetList::Create(SavedAsset asset) std::unique_ptr<Asset> AssetList::CreateAndLoad(SavedAsset assetIn) { auto& savedAsset = Create(std::move(assetIn)); - auto asset = std::unique_ptr<Asset>(mLoader->CreateEmpty(savedAsset)); + auto asset = std::unique_ptr<Asset>(CreateEmptyInstance(savedAsset)); return asset; } -std::unique_ptr<Asset> AssetList::LoadFromDisk(std::string_view name) const +std::unique_ptr<Asset> AssetList::Load(std::string_view name) const { if (auto savedAsset = FindByName(name)) { - auto asset = mLoader->LoadUnique(*savedAsset); + auto asset = Load(*savedAsset); return asset; + } else { + return nullptr; } } -bool AssetList::Rename(std::string_view oldName, std::string_view newName) +std::unique_ptr<Asset> AssetList::Load(const SavedAsset& asset) const +{ + return std::unique_ptr<Asset>(LoadImpl(asset)); +} + +const SavedAsset* AssetList::Rename(std::string_view oldName, std::string_view newName) { + auto iter = mAssets.find(oldName); + if (iter == mAssets.end()) return nullptr; + + auto info = std::move(iter.value()); + info.Name = newName; + + auto [newIter, DISCARD] = mAssets.insert(newName, std::move(info)); + mAssets.erase(iter); + + return &newIter.value(); } bool AssetList::Remove(std::string_view name) { + auto iter = mAssets.find(name); + if (iter == mAssets.end()) { + return false; + } + auto& asset = iter.value(); + + fs::remove(RetrievePathFromAsset(asset)); + mAssets.erase(iter); + + return true; } int AssetList::GetCacheSizeLimit() const @@ -110,17 +103,42 @@ void AssetList::SetCacheSizeLimit(int limit) mCacheSizeLimit = limit; } -void AssetList::DrawBigIcons(DrawState& state) +void AssetList::DrawBigIcons(ListState& state) { // TODO } -void AssetList::DrawDetails(DrawState& state) +void AssetList::DrawDetails(ListState& state) { - mLoader->SetupDetailsTable("AssetDetailsTable"); + SetupDetailsTable("AssetDetailsTable"); for (auto& asset : mAssets) { - mLoader->DrawDetailsTableRow(asset); + DrawDetailsTableRow(asset); ImGui::TableNextRow(); } ImGui::EndTable(); } + +void AssetList::DiscoverFilesByExtension(const std::function<void(SavedAsset)>& 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<void(SavedAsset)>& callback, const fs::path& containerDir, const std::function<bool(std::istream&)>& validater) const +{ + // TODO +} diff --git a/core/src/Model/Assets.hpp b/core/src/Model/Assets.hpp index bc5219d..3401e42 100644 --- a/core/src/Model/Assets.hpp +++ b/core/src/Model/Assets.hpp @@ -1,18 +1,22 @@ #pragma once #include <tsl/array_map.h> +#include <uuid.h> #include <filesystem> #include <iosfwd> #include <memory> #include <string_view> /// A structure representing a ready-to-be-loaded asset, locating on the disk. +/// Each asset should be identified by a unique uuid within the asset category (i.e. a workflow and a template can share the same uuid), +/// generated on insertion to an asset list if not given by the caller. struct SavedAsset { - std::filesystem::path Path; std::string Name; - /// `Path`'s string form, encoded in UTF-8. - std::string PathString = Path.string(); + /// UUID of this asset. This field is generated as a random UUID v4 upon insertion into an AssetList, if not already provided by the caller (indicated by !is_nil()). + uuids::uuid Uuid; + /// Extra data to be used by the AssetList/Asset implementation. + uint64_t Payload; }; class Asset @@ -22,40 +26,15 @@ public: virtual ~Asset() = default; }; -class AssetCategory -{ -public: - virtual ~AssetCategory() = default; - - virtual void DiscoverFiles(const std::function<void(SavedAsset)>& callback) const = 0; - - virtual Asset* CreateEmpty(const SavedAsset& diskForm) const = 0; - std::unique_ptr<Asset> CreateEmptyUnique(const SavedAsset& diskForm) const; - virtual Asset* Load(const SavedAsset& diskForm) const = 0; - std::unique_ptr<Asset> 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<void(SavedAsset)>& callback, const std::filesystem::path& containerDir, std::string_view extension); - static void DiscoverFilesByHeader(const std::function<void(SavedAsset)>& callback, const std::filesystem::path& containerDir, const std::function<bool(std::istream&)>& validater); -}; - class AssetList { private: - const AssetCategory* mLoader; tsl::array_map<char, SavedAsset> mAssets; tsl::array_map<char, std::unique_ptr<Asset>> mCache; int mCacheSizeLimit = 0; public: - AssetList(const AssetCategory& loader); + virtual ~AssetList() = default; // TODO support file watches void Reload(); @@ -63,42 +42,62 @@ public: const SavedAsset* FindByName(std::string_view name) const; const SavedAsset& Create(SavedAsset asset); std::unique_ptr<Asset> CreateAndLoad(SavedAsset asset); - std::unique_ptr<Asset> LoadFromDisk(std::string_view name) const; - bool Rename(std::string_view oldName, std::string_view newName); + /// Load the asset on disk by its name. + std::unique_ptr<Asset> Load(std::string_view name) const; + /// Load the asset on disk by a reference to its SavedAsset instance. This function assumes that the given SavedAsset + /// is stored in AssetList, otherwise the behavior is undefined. + std::unique_ptr<Asset> Load(const SavedAsset& asset) const; + const SavedAsset* Rename(std::string_view oldName, std::string_view newName); bool Remove(std::string_view name); int GetCacheSizeLimit() const; void SetCacheSizeLimit(int limit); - struct DrawState + struct ListState { const SavedAsset* SelectedAsset = nullptr; }; - void DrawBigIcons(DrawState& state); - void DrawDetails(DrawState& state); + void DrawBigIcons(ListState& state); + void DrawDetails(ListState& state); + +protected: + virtual void DiscoverFiles(const std::function<void(SavedAsset)>& callback) const = 0; + + // Helper + void DiscoverFilesByExtension(const std::function<void(SavedAsset)>& callback, const std::filesystem::path& containerDir, std::string_view extension) const; + void DiscoverFilesByHeader(const std::function<void(SavedAsset)>& callback, const std::filesystem::path& containerDir, const std::function<bool(std::istream&)>& validater) const; + + virtual void SaveEmptyInstance(const SavedAsset& asset) const = 0; + virtual Asset* CreateEmptyInstance(const SavedAsset& asset) const = 0; + + virtual Asset* LoadImpl(const SavedAsset& asset) const = 0; + + virtual std::string RetrieveNameFromFile(const std::filesystem::path& file) const = 0; + virtual uuids::uuid RetrieveUuidFromFile(const std::filesystem::path& file) const = 0; + virtual std::filesystem::path RetrievePathFromAsset(const SavedAsset& asset) const = 0; + + /// 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; }; -template <class TAsset> -class TypedAssetList : public AssetList +template <class T> +class AssetListTyped : public AssetList { public: - using Asset = TAsset; - using AssetType = typename TAsset::CategoryType; - -public: - // Import constructor - using AssetList::AssetList; - - Asset* FindByName(std::string_view name) const + std::unique_ptr<T> CreateAndLoad(SavedAsset asset) { - return static_cast<TAsset*>(AssetList::FindByName(name)); + return std::unique_ptr<T>(static_cast<T*>(AssetList::CreateAndLoad(asset).release())); } - std::unique_ptr<Asset> Create(std::string_view name) + + std::unique_ptr<T> Load(std::string_view name) const { - return std::unique_ptr<TAsset>(static_cast<TAsset*>(AssetList::Create(name).release())); + return std::unique_ptr<T>(static_cast<T*>(AssetList::Load(name).release())); } - std::unique_ptr<Asset> LoadFromDisk(std::string_view name) const + + std::unique_ptr<T> Load(const SavedAsset& asset) const { - return std::unique_ptr<TAsset>(static_cast<TAsset>(AssetList::LoadFromDisk(name))); + return std::unique_ptr<T>(static_cast<T*>(AssetList::Load(asset).release())); } }; diff --git a/core/src/Model/Project.hpp b/core/src/Model/Project.hpp index fea148d..8cf3483 100644 --- a/core/src/Model/Project.hpp +++ b/core/src/Model/Project.hpp @@ -15,8 +15,8 @@ class Project { public: - TypedAssetList<Workflow> Workflows; - TypedAssetList<Template> Templates; + WorkflowAssetList Workflows; + TemplateAssetList Templates; ItemList<ProductItem> Products; ItemList<FactoryItem> Factories; ItemList<CustomerItem> Customers; diff --git a/core/src/Model/Template/Template.hpp b/core/src/Model/Template/Template.hpp index d876650..600bb26 100644 --- a/core/src/Model/Template/Template.hpp +++ b/core/src/Model/Template/Template.hpp @@ -19,8 +19,7 @@ public: KindCount = InvalidKind, }; - using CategoryType = TemplateAssetCategory; - static constinit const TemplateAssetCategory Category; + using CategoryType = TemplateAssetList; private: Kind mKind; @@ -45,12 +44,20 @@ public: virtual void WriteTo(std::ostream& stream) const = 0; }; -class TemplateAssetCategory : public AssetCategory +class TemplateAssetList final : public AssetListTyped<Template> { -public: +protected: virtual void DiscoverFiles(const std::function<void(SavedAsset)>& callback) const override; - virtual Template* CreateEmpty(const SavedAsset& diskForm) const override; - virtual Template* Load(const SavedAsset& diskForm) const override; + + virtual std::string RetrieveNameFromFile(const std::filesystem::path& file) const override; + virtual uuids::uuid RetrieveUuidFromFile(const std::filesystem::path& file) const override; + virtual std::filesystem::path RetrievePathFromAsset(const SavedAsset& asset) const override; + + virtual void SaveEmptyInstance(const SavedAsset& asset) const override; + virtual Template* CreateEmptyInstance(const SavedAsset& diskForm) const override; + + virtual Template* LoadImpl(const SavedAsset& diskForm) const override; + virtual void SetupDetailsTable(const char* tableId) const override; virtual void DrawBigIcon(const SavedAsset& asset) const override; virtual void DrawDetailsTableRow(const SavedAsset& asset) const override; diff --git a/core/src/Model/Template/Template_Main.cpp b/core/src/Model/Template/Template_Main.cpp index 9efbeae..92ad050 100644 --- a/core/src/Model/Template/Template_Main.cpp +++ b/core/src/Model/Template/Template_Main.cpp @@ -4,11 +4,11 @@ #include "Model/Project.hpp" #include <imgui.h> +#include <uuid.h> #include <fstream> using namespace std::literals::string_view_literals; - -constinit const TemplateAssetCategory Template::Category{}; +namespace fs = std::filesystem; Template::Template(Kind kind) : mKind{ kind } @@ -20,26 +20,62 @@ Template::Kind Template::GetKind() const return mKind; } -void TemplateAssetCategory::DiscoverFiles(const std::function<void(SavedAsset)>& callback) const +void TemplateAssetList::DiscoverFiles(const std::function<void(SavedAsset)>& callback) const { auto& gs = GlobalStates::GetInstance(); DiscoverFilesByExtension(callback, gs.GetCurrentProject()->GetTemplatesDirectory(), ".cplt-template"sv); } -Template* TemplateAssetCategory::CreateEmpty(const SavedAsset& diskForm) const +std::string TemplateAssetList::RetrieveNameFromFile(const fs::path& file) const { - // TODO + std::ifstream ifs(file); + if (!ifs) return ""; + + std::string name; + ifs >> name; + return name; +} + +uuids::uuid TemplateAssetList::RetrieveUuidFromFile(const fs::path& file) const +{ + return uuids::uuid::from_string(file.stem().string()); } -Template* TemplateAssetCategory::Load(const SavedAsset& diskForm) const +fs::path TemplateAssetList::RetrievePathFromAsset(const SavedAsset& asset) const { - std::ifstream ifs(diskForm.Path); + auto uuid = uuids::uuid_random_generator{}(); + auto fileName = uuids::to_string(uuid); + fileName.append(".cplt-template"); + + auto& gs = GlobalStates::GetInstance(); + return gs.GetCurrentProject()->GetTemplatePath(fileName); +} + +void TemplateAssetList::SaveEmptyInstance(const SavedAsset& asset) const +{ + auto path = RetrievePathFromAsset(asset); + + std::ofstream ofs(path); + if (!ofs) return; + ofs << asset.Name; + ofs << static_cast<Template::Kind>(asset.Payload); +} + +Template* TemplateAssetList::CreateEmptyInstance(const SavedAsset& asset) const +{ + auto kind = static_cast<Template::Kind>(asset.Payload); + return Template::CreateByKind(kind).release(); +} + +Template* TemplateAssetList::LoadImpl(const SavedAsset& asset) const +{ + std::ifstream ifs(RetrievePathFromAsset(asset)); if (!ifs) return nullptr; uint32_t iKind; ifs >> iKind; - auto kind = (Template::Kind)iKind; + auto kind = static_cast<Template::Kind>(iKind); auto tmpl = Template::CreateByKind(kind); auto res = tmpl->ReadFrom(ifs); @@ -50,7 +86,7 @@ Template* TemplateAssetCategory::Load(const SavedAsset& diskForm) const return tmpl.release(); } -void TemplateAssetCategory::SetupDetailsTable(const char* tableId) const +void TemplateAssetList::SetupDetailsTable(const char* tableId) const { ImGui::BeginTable(tableId, 3); @@ -60,19 +96,19 @@ void TemplateAssetCategory::SetupDetailsTable(const char* tableId) const ImGui::TableHeadersRow(); } -void TemplateAssetCategory::DrawBigIcon(const SavedAsset& asset) const +void TemplateAssetList::DrawBigIcon(const SavedAsset& asset) const { // TODO } -void TemplateAssetCategory::DrawDetailsTableRow(const SavedAsset& asset) const +void TemplateAssetList::DrawDetailsTableRow(const SavedAsset& asset) const { ImGui::TableNextColumn(); ImGui::TextUnformatted(asset.Name.c_str()); ImGui::TableNextColumn(); - // TODO - //ImGui::TextUnformatted(Template::FormatKind(asset.)); + auto kind = static_cast<Template::Kind>(asset.Payload); + ImGui::TextUnformatted(Template::FormatKind(kind)); ImGui::TableNextColumn(); // TODO diff --git a/core/src/Model/Template/fwd.hpp b/core/src/Model/Template/fwd.hpp index aad9f14..b0acb28 100644 --- a/core/src/Model/Template/fwd.hpp +++ b/core/src/Model/Template/fwd.hpp @@ -8,4 +8,4 @@ class TableTemplate; // Template.hpp class Template; -class TemplateAssetCategory; +class TemplateAssetList; diff --git a/core/src/Model/Workflow/Workflow.hpp b/core/src/Model/Workflow/Workflow.hpp index 51596e5..8b3db8a 100644 --- a/core/src/Model/Workflow/Workflow.hpp +++ b/core/src/Model/Workflow/Workflow.hpp @@ -178,8 +178,8 @@ protected: class Workflow : public Asset { public: - using CategoryType = WorkflowAssetCategory; - static constinit const WorkflowAssetCategory Category; + using CategoryType = WorkflowAssetList; + static constinit const WorkflowAssetList Category; private: friend class WorkflowNode; @@ -276,12 +276,20 @@ private: std::pair<std::unique_ptr<WorkflowNode>&, size_t> AllocWorkflowStep(); }; -class WorkflowAssetCategory : public AssetCategory +class WorkflowAssetList final : public AssetListTyped<Workflow> { public: virtual void DiscoverFiles(const std::function<void(SavedAsset)>& callback) const override; - virtual Workflow* CreateEmpty(const SavedAsset& diskForm) const override; - virtual Workflow* Load(const SavedAsset& diskForm) const override; + + virtual std::string RetrieveNameFromFile(const std::filesystem::path& file) const override; + virtual uuids::uuid RetrieveUuidFromFile(const std::filesystem::path& file) const override; + virtual std::filesystem::path RetrievePathFromAsset(const SavedAsset& asset) const override; + + virtual void SaveEmptyInstance(const SavedAsset& asset) const override; + virtual Workflow* CreateEmptyInstance(const SavedAsset& diskForm) const override; + + virtual Workflow* LoadImpl(const SavedAsset& diskForm) const override; + virtual void SetupDetailsTable(const char* tableId) const override; virtual void DrawBigIcon(const SavedAsset& asset) const override; virtual void DrawDetailsTableRow(const SavedAsset& asset) const override; diff --git a/core/src/Model/Workflow/Workflow_Main.cpp b/core/src/Model/Workflow/Workflow_Main.cpp index 0875f11..202818f 100644 --- a/core/src/Model/Workflow/Workflow_Main.cpp +++ b/core/src/Model/Workflow/Workflow_Main.cpp @@ -6,6 +6,7 @@ #include <imgui.h> #include <imgui_node_editor.h> #include <tsl/robin_set.h> +#include <uuid.h> #include <cassert> #include <fstream> #include <iostream> @@ -13,6 +14,7 @@ #include <utility> using namespace std::literals::string_view_literals; +namespace fs = std::filesystem; namespace ImNodes = ax::NodeEditor; WorkflowConnection::WorkflowConnection() @@ -324,51 +326,6 @@ void WorkflowNode::OnDetach() { } -constinit const WorkflowAssetCategory Workflow::Category{}; - -void WorkflowAssetCategory::DiscoverFiles(const std::function<void(SavedAsset)>& callback) const -{ - auto& gs = GlobalStates::GetInstance(); - DiscoverFilesByExtension(callback, gs.GetCurrentProject()->GetWorkflowsDirectory(), ".cplt-workflow"sv); -} - -Workflow* WorkflowAssetCategory::CreateEmpty(const SavedAsset& diskForm) const -{ - // TODO -} - -Workflow* WorkflowAssetCategory::Load(const SavedAsset& diskForm) const -{ - std::ifstream ifs(diskForm.Path); - if (!ifs) return nullptr; - - auto workflow = std::make_unique<Workflow>(); - if (workflow->ReadFrom(ifs) != Workflow::RR_Success) { - return nullptr; - } - - return workflow.release(); -} - -void WorkflowAssetCategory::SetupDetailsTable(const char* tableId) const -{ - ImGui::BeginTable(tableId, 2); - - ImGui::TableSetupColumn("Name"); - ImGui::TableSetupColumn("Modified time"); - ImGui::TableHeadersRow(); -} - -void WorkflowAssetCategory::DrawBigIcon(const SavedAsset& asset) const -{ - // TODO -} - -void WorkflowAssetCategory::DrawDetailsTableRow(const SavedAsset& asset) const -{ - // TODO -} - const std::vector<WorkflowConnection>& Workflow::GetConnections() const { return mConnections; @@ -753,16 +710,6 @@ void Workflow::WriteTo(std::ostream& stream) } } -void Workflow::DrawBigIcon() const -{ - // TODO -} - -void Workflow::DrawDetailTableRow() const -{ - // TODO -} - std::pair<WorkflowConnection&, size_t> Workflow::AllocWorkflowConnection() { for (size_t idx = 0; idx < mConnections.size(); ++idx) { @@ -793,3 +740,80 @@ std::pair<std::unique_ptr<WorkflowNode>&, size_t> Workflow::AllocWorkflowStep() return { node, id }; } + +void WorkflowAssetList::DiscoverFiles(const std::function<void(SavedAsset)>& callback) const +{ + auto& gs = GlobalStates::GetInstance(); + DiscoverFilesByExtension(callback, gs.GetCurrentProject()->GetWorkflowsDirectory(), ".cplt-workflow"sv); +} + +std::string WorkflowAssetList::RetrieveNameFromFile(const fs::path& file) const +{ + std::ifstream ifs(file); + if (!ifs) return ""; + + std::string name; + ifs >> name; + return name; +} + +uuids::uuid WorkflowAssetList::RetrieveUuidFromFile(const fs::path& file) const +{ + return uuids::uuid::from_string(file.stem().string()); +} + +fs::path WorkflowAssetList::RetrievePathFromAsset(const SavedAsset& asset) const +{ + auto uuid = uuids::uuid_random_generator{}(); + auto fileName = uuids::to_string(uuid); + fileName.append(".cplt-workflow"); + + auto& gs = GlobalStates::GetInstance(); + return gs.GetCurrentProject()->GetTemplatePath(fileName); +} + +void WorkflowAssetList::SaveEmptyInstance(const SavedAsset& asset) const +{ + auto path = RetrievePathFromAsset(asset); + + std::ofstream ofs(path); + if (!ofs) return; + ofs << asset.Name; +} + +Workflow* WorkflowAssetList::CreateEmptyInstance(const SavedAsset& asset) const +{ + return new Workflow(); +} + +Workflow* WorkflowAssetList::LoadImpl(const SavedAsset& asset) const +{ + std::ifstream ifs(RetrievePathFromAsset(asset)); + if (!ifs) return nullptr; + + auto workflow = std::make_unique<Workflow>(); + if (workflow->ReadFrom(ifs) != Workflow::RR_Success) { + return nullptr; + } + + return workflow.release(); +} + +void WorkflowAssetList::SetupDetailsTable(const char* tableId) const +{ + ImGui::BeginTable(tableId, 2); + + ImGui::TableSetupColumn("Name"); + ImGui::TableSetupColumn("Modified time"); + ImGui::TableHeadersRow(); +} + +void WorkflowAssetList::DrawBigIcon(const SavedAsset& asset) const +{ + // TODO +} + +void WorkflowAssetList::DrawDetailsTableRow(const SavedAsset& asset) const +{ + // TODO +} diff --git a/core/src/Model/Workflow/fwd.hpp b/core/src/Model/Workflow/fwd.hpp index 8f0263d..ed39bdb 100644 --- a/core/src/Model/Workflow/fwd.hpp +++ b/core/src/Model/Workflow/fwd.hpp @@ -19,4 +19,4 @@ class BaseObjectValue; class WorkflowConnection; class WorkflowNode; class Workflow; -class WorkflowAssetCategory; +class WorkflowAssetList; diff --git a/core/src/Model/fwd.hpp b/core/src/Model/fwd.hpp index ba7b156..2028cbb 100644 --- a/core/src/Model/fwd.hpp +++ b/core/src/Model/fwd.hpp @@ -13,10 +13,7 @@ class MainDatabase; // Assets.hpp struct SavedAsset; class Asset; -class AssetCategory; class AssetList; -template <class T> -class TypedAssetList; // Filter.hpp class TableRowsFilter; diff --git a/core/src/UI/UI_Templates.cpp b/core/src/UI/UI_Templates.cpp index 7ebb9e1..def50d9 100644 --- a/core/src/UI/UI_Templates.cpp +++ b/core/src/UI/UI_Templates.cpp @@ -140,7 +140,7 @@ void UI::TemplatesTab() bool openedDummy = true; static std::unique_ptr<TemplateUI> openTemplate; - static AssetList::DrawState state; + static AssetList::ListState state; // Toolbar item: close if (ImGui::Button(ls->Close.Get(), openTemplate == nullptr)) { @@ -156,8 +156,8 @@ void UI::TemplatesTab() project.Templates.DrawDetails(state); if (state.SelectedAsset) { - auto kind = state.SelectedAsset->Kind; - auto tmpl = state.SelectedAsset->LoadFromDisk(); + auto kind = static_cast<Template::Kind>(state.SelectedAsset->Payload); + auto tmpl = project.Templates.Load(*state.SelectedAsset); openTemplate = TemplateUI::CreateByKind(kind, std::move(tmpl)); } @@ -186,8 +186,7 @@ void UI::TemplatesTab() newNameError = NameSelectionError::Empty; } - auto& templates = gs.GetCurrentProject()->GetTemplates(); - if (templates.find(newName) != templates.end()) { + if (project.Templates.FindByName(newName)) { newNameError = NameSelectionError::Duplicated; } }; @@ -233,13 +232,10 @@ void UI::TemplatesTab() } if (ImGui::Button(ls->DialogConfirm.Get(), IsInputValid())) { - project.InsertTemplate( - newName, - TemplateInfo{ - .Path = project.GetTemplatePath(newName), - .Name = newName, // Don't std::move here because evaluation order of `newName` (as parameter of InsertTemplate()) and this is unspecified - .Kind = newKind, - }); + project.Templates.Create(SavedAsset{ + .Name = newName, + .Payload = static_cast<uint64_t>(newKind), + }); openTemplate = TemplateUI::CreateByKind(newKind); } @@ -255,7 +251,7 @@ void UI::TemplatesTab() } ImGui::SameLine(); - if (ImGui::Button(ls->Rename.Get(), state.SelectedTemplate == nullptr)) { + if (ImGui::Button(ls->Rename.Get(), state.SelectedAsset == nullptr)) { ImGui::OpenPopup("Rename template"); newName.clear(); } @@ -265,14 +261,12 @@ void UI::TemplatesTab() } if (ImGui::Button(ls->DialogConfirm.Get(), IsInputValid())) { - auto& project = *gs.GetCurrentProject(); - - project.Templates.Rename( - state.SelectedTemplate->Name, + auto tmpl = project.Templates.Rename( + state.SelectedAsset->Name, newName); - // We mutated the map, the pointer may be invalid now - state.SelectedTemplate = &project.GetTemplates().at(newName); + // Update the selected pointer to the new location (we mutated the map, the pointer may be invalid now) + state.SelectedAsset = tmpl; } ImGui::SameLine(); if (ImGui::Button(ls->DialogCancel.Get())) { @@ -285,14 +279,15 @@ void UI::TemplatesTab() } ImGui::SameLine(); - if (ImGui::Button(ls->Delete.Get(), state.SelectedTemplate == nullptr)) { + if (ImGui::Button(ls->Delete.Get(), state.SelectedAsset == nullptr)) { ImGui::OpenPopup("Delete confirmation"); } if (ImGui::BeginPopupModal("Delete confirmation")) { - assert(state.SelectedTemplate != nullptr); - if (ImGui::Button(ls->DialogConfirm.Get())) { - gs.GetCurrentProject()->RemoveTemplate(state.SelectedTemplate->Name); + auto& assetName = state.SelectedAsset->Name; + project.Templates.Remove(assetName); + + state.SelectedAsset = nullptr; } ImGui::SameLine(); if (ImGui::Button(ls->DialogCancel.Get())) { diff --git a/core/src/UI/UI_Workflows.cpp b/core/src/UI/UI_Workflows.cpp index 51cc4f8..7b2de2a 100644 --- a/core/src/UI/UI_Workflows.cpp +++ b/core/src/UI/UI_Workflows.cpp @@ -358,39 +358,17 @@ public: ImNodes::End(); } }; - -struct DrawTemplateList_State -{ - const WorkflowInfo* SelectedWorkflow = nullptr; -}; - -void DrawTemplateList(DrawTemplateList_State& state) -{ - auto& gs = GlobalStates::GetInstance(); - auto& workflows = gs.GetCurrentProject()->GetWorkflows(); - - // TODO sort the list - for (auto& info : workflows) { - if (ImGui::Selectable(info.Name.c_str(), state.SelectedWorkflow == &info)) { - state.SelectedWorkflow = &info; - } - if (ImGui::IsItemHovered()) { - ImGui::BeginTooltip(); - ImGui::Text("Path: %s", info.PathStringCache.c_str()); - ImGui::EndTooltip(); - } - } -} } // namespace void UI::WorkflowsTab() { auto ls = LocaleStrings::Instance.get(); auto& gs = GlobalStates::GetInstance(); + auto& project = *gs.GetCurrentProject(); bool openedDummy = true; static std::unique_ptr<WorkflowUI> openWorkflow; - static DrawTemplateList_State state; + static AssetList::ListState state; // Toolbar item: close if (ImGui::Button(ls->Close.Get(), openWorkflow == nullptr)) { @@ -403,10 +381,10 @@ void UI::WorkflowsTab() ImGui::OpenPopup(ls->OpenWorkflowDialogTitle.Get()); } if (ImGui::BeginPopupModal(ls->OpenWorkflowDialogTitle.Get(), &openedDummy, ImGuiWindowFlags_AlwaysAutoResize)) { - DrawTemplateList(state); + project.Workflows.DrawDetails(state); - if (state.SelectedWorkflow) { - auto workflow = state.SelectedWorkflow->LoadFromDisk(); + if (state.SelectedAsset) { + auto workflow = project.Workflows.Load(*state.SelectedAsset); openWorkflow = std::make_unique<WorkflowUI>(std::move(workflow)); } @@ -419,7 +397,7 @@ void UI::WorkflowsTab() ImGui::OpenPopup(ls->ManageWorkflowsDialogTitle.Get()); } if (ImGui::BeginPopupModal(ls->ManageWorkflowsDialogTitle.Get(), &openedDummy, ImGuiWindowFlags_AlwaysAutoResize)) { - DrawTemplateList(state); + project.Workflows.DrawDetails(state); enum class NameSelectionError { @@ -429,7 +407,7 @@ void UI::WorkflowsTab() }; static std::string newName; static NameSelectionError newNameError; - if (ImGui::Button(ls->Rename.Get(), state.SelectedWorkflow == nullptr)) { + if (ImGui::Button(ls->Rename.Get(), state.SelectedAsset == nullptr)) { ImGui::OpenPopup("Rename workflow"); newName.clear(); } @@ -439,16 +417,17 @@ void UI::WorkflowsTab() newNameError = NameSelectionError::Empty; } - auto& workflows = gs.GetCurrentProject()->GetWorkflows(); - if (workflows.find(newName) != workflows.end()) { + if (project.Workflows.FindByName(newName)) { newNameError = NameSelectionError::Duplicated; } } if (ImGui::Button(ls->DialogConfirm.Get(), newName.empty())) { - auto project = gs.GetCurrentProject(); - project->RenameWorkflow(state.SelectedWorkflow->Name, newName); - state.SelectedWorkflow = &project->GetWorkflows().at(newName); + auto workflow = project.Workflows.Rename( + state.SelectedAsset->Name, + newName); + + state.SelectedAsset = workflow; } ImGui::SameLine(); if (ImGui::Button(ls->DialogCancel.Get())) { @@ -468,12 +447,15 @@ void UI::WorkflowsTab() ImGui::EndPopup(); } - if (ImGui::Button(ls->Delete.Get(), state.SelectedWorkflow == nullptr)) { + if (ImGui::Button(ls->Delete.Get(), state.SelectedAsset == nullptr)) { ImGui::OpenPopup("Delete confirmation"); } if (ImGui::BeginPopupModal("Delete confirmation")) { if (ImGui::Button(ls->DialogConfirm.Get())) { - gs.GetCurrentProject()->RemoveWorkflow(state.SelectedWorkflow->Name); + auto& assetName = state.SelectedAsset->Name; + project.Workflows.Remove(assetName); + + state.SelectedAsset = nullptr; } ImGui::SameLine(); if (ImGui::Button(ls->DialogCancel.Get())) { |