Support writing asset library definitions to the project settings
Unit tested, there is no UI for this yet.
This commit is contained in:
parent
378e0d96fc
commit
97e21ed248
|
@ -13,12 +13,15 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
#include "BLI_compiler_attrs.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
struct CustomAssetLibraryDefinition;
|
||||
struct ListBase;
|
||||
|
||||
struct CustomAssetLibraryDefinition *BKE_asset_library_custom_add(
|
||||
struct ListBase *custom_libraries, const char *name, const char *path) ATTR_NONNULL(1);
|
||||
struct ListBase *custom_libraries,
|
||||
const char *name CPP_ARG_DEFAULT(nullptr),
|
||||
const char *path CPP_ARG_DEFAULT(nullptr)) ATTR_NONNULL(1);
|
||||
/**
|
||||
* Unlink and free a library preference member.
|
||||
* \note Free's \a library itself.
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <memory>
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_string_ref.hh"
|
||||
|
||||
namespace blender::io::serialize {
|
||||
|
@ -17,6 +18,7 @@ class DictionaryValue;
|
|||
namespace blender::bke {
|
||||
|
||||
class ProjectSettings;
|
||||
struct CustomAssetLibraries;
|
||||
|
||||
class BlenderProject {
|
||||
inline static std::unique_ptr<BlenderProject> active_;
|
||||
|
@ -48,6 +50,7 @@ class ProjectSettings {
|
|||
/* Path to the project root using slashes in the OS native format. */
|
||||
std::string project_root_path_;
|
||||
std::string project_name_;
|
||||
std::unique_ptr<CustomAssetLibraries> asset_libraries_;
|
||||
bool has_unsaved_changes_ = false;
|
||||
|
||||
public:
|
||||
|
@ -90,10 +93,18 @@ class ProjectSettings {
|
|||
auto project_root_path [[nodiscard]] () const -> StringRefNull;
|
||||
void project_name(StringRef new_name);
|
||||
auto project_name [[nodiscard]] () const -> StringRefNull;
|
||||
auto asset_library_definitions() const -> const ListBase &;
|
||||
auto has_unsaved_changes [[nodiscard]] () const -> bool;
|
||||
|
||||
private:
|
||||
auto to_dictionary() const -> std::unique_ptr<io::serialize::DictionaryValue>;
|
||||
};
|
||||
|
||||
struct CustomAssetLibraries {
|
||||
ListBase asset_libraries = {nullptr, nullptr}; /* CustomAssetLibraryDefinition */
|
||||
|
||||
CustomAssetLibraries(ListBase asset_libraries);
|
||||
~CustomAssetLibraries();
|
||||
};
|
||||
|
||||
} // namespace blender::bke
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include <fstream>
|
||||
|
||||
#include "BKE_asset_library_custom.h"
|
||||
#include "BKE_blender_project.h"
|
||||
#include "BKE_blender_project.hh"
|
||||
|
||||
|
@ -109,6 +110,7 @@ static bool path_contains_project_settings(StringRef path)
|
|||
|
||||
struct ExtractedSettings {
|
||||
std::string project_name;
|
||||
ListBase asset_libraries = {nullptr, nullptr}; /* CustomAssetLibraryDefinition */
|
||||
};
|
||||
|
||||
static std::unique_ptr<serialize::Value> read_settings_file(StringRef settings_filepath)
|
||||
|
@ -139,14 +141,60 @@ static std::unique_ptr<ExtractedSettings> extract_settings(
|
|||
std::unique_ptr extracted_settings = std::make_unique<ExtractedSettings>();
|
||||
|
||||
const DictionaryValue::Lookup attributes = dictionary.create_lookup();
|
||||
const DictionaryValue::LookupValue *project_value = attributes.lookup_ptr("project");
|
||||
BLI_assert(project_value != nullptr);
|
||||
|
||||
const DictionaryValue *project_dict = (*project_value)->as_dictionary_value();
|
||||
const StringValue *project_name_value =
|
||||
project_dict->create_lookup().lookup("name")->as_string_value();
|
||||
if (project_name_value) {
|
||||
extracted_settings->project_name = project_name_value->value();
|
||||
/* "project": */ {
|
||||
const DictionaryValue::LookupValue *project_value = attributes.lookup_ptr("project");
|
||||
BLI_assert(project_value != nullptr);
|
||||
|
||||
const DictionaryValue *project_dict = (*project_value)->as_dictionary_value();
|
||||
const StringValue *project_name_value =
|
||||
project_dict->create_lookup().lookup("name")->as_string_value();
|
||||
if (project_name_value) {
|
||||
extracted_settings->project_name = project_name_value->value();
|
||||
}
|
||||
}
|
||||
/* "asset_libraries": */ {
|
||||
const DictionaryValue::LookupValue *asset_libraries_value = attributes.lookup_ptr(
|
||||
"asset_libraries");
|
||||
if (asset_libraries_value) {
|
||||
const ArrayValue *asset_libraries_array = (*asset_libraries_value)->as_array_value();
|
||||
if (!asset_libraries_array) {
|
||||
throw std::runtime_error(
|
||||
"Unexpected asset_library format in settings.json, expected array");
|
||||
}
|
||||
|
||||
for (const ArrayValue::Item &element : asset_libraries_array->elements()) {
|
||||
const DictionaryValue *object_value = element->as_dictionary_value();
|
||||
if (!object_value) {
|
||||
throw std::runtime_error(
|
||||
"Unexpected asset_library entry in settings.json, expected dictionary entries only");
|
||||
}
|
||||
const DictionaryValue::Lookup element_lookup = object_value->create_lookup();
|
||||
const DictionaryValue::LookupValue *name_value = element_lookup.lookup_ptr("name");
|
||||
if (name_value && (*name_value)->type() != eValueType::String) {
|
||||
throw std::runtime_error(
|
||||
"Unexpected asset_library entry in settings.json, expected name to be string");
|
||||
}
|
||||
const DictionaryValue::LookupValue *path_value = element_lookup.lookup_ptr("path");
|
||||
if (path_value && (*path_value)->type() != eValueType::String) {
|
||||
throw std::runtime_error(
|
||||
"Unexpected asset_library entry in settings.json, expected path to be string");
|
||||
}
|
||||
|
||||
CustomAssetLibraryDefinition *library = BKE_asset_library_custom_add(
|
||||
&extracted_settings->asset_libraries);
|
||||
/* Name or path may not be set, this is fine. */
|
||||
if (name_value) {
|
||||
std::string name = (*name_value)->as_string_value()->value();
|
||||
BKE_asset_library_custom_name_set(
|
||||
&extracted_settings->asset_libraries, library, name.c_str());
|
||||
}
|
||||
if (path_value) {
|
||||
std::string path = (*path_value)->as_string_value()->value();
|
||||
BKE_asset_library_custom_path_set(library, path.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return extracted_settings;
|
||||
|
@ -203,6 +251,9 @@ std::unique_ptr<ProjectSettings> ProjectSettings::load_from_disk(StringRef proje
|
|||
std::unique_ptr loaded_settings = std::make_unique<ProjectSettings>(paths.project_root_path);
|
||||
if (extracted_settings) {
|
||||
loaded_settings->project_name_ = extracted_settings->project_name;
|
||||
/* Moves ownership. */
|
||||
loaded_settings->asset_libraries_ = std::make_unique<CustomAssetLibraries>(
|
||||
extracted_settings->asset_libraries);
|
||||
}
|
||||
|
||||
return loaded_settings;
|
||||
|
@ -214,10 +265,29 @@ std::unique_ptr<serialize::DictionaryValue> ProjectSettings::to_dictionary() con
|
|||
|
||||
std::unique_ptr<DictionaryValue> root = std::make_unique<DictionaryValue>();
|
||||
DictionaryValue::Items &root_attributes = root->elements();
|
||||
std::unique_ptr<DictionaryValue> project_dict = std::make_unique<DictionaryValue>();
|
||||
DictionaryValue::Items &project_attributes = project_dict->elements();
|
||||
project_attributes.append_as("name", new StringValue(project_name_));
|
||||
root_attributes.append_as("project", std::move(project_dict));
|
||||
|
||||
/* "project": */ {
|
||||
std::unique_ptr<DictionaryValue> project_dict = std::make_unique<DictionaryValue>();
|
||||
DictionaryValue::Items &project_attributes = project_dict->elements();
|
||||
project_attributes.append_as("name", new StringValue(project_name_));
|
||||
root_attributes.append_as("project", std::move(project_dict));
|
||||
}
|
||||
/* "asset_libraries": */ {
|
||||
if (asset_libraries_ && !BLI_listbase_is_empty(&asset_libraries_->asset_libraries)) {
|
||||
std::unique_ptr<ArrayValue> asset_libs_array = std::make_unique<ArrayValue>();
|
||||
ArrayValue::Items &asset_libs_elements = asset_libs_array->elements();
|
||||
LISTBASE_FOREACH (
|
||||
const CustomAssetLibraryDefinition *, library, &asset_libraries_->asset_libraries) {
|
||||
std::unique_ptr<DictionaryValue> library_dict = std::make_unique<DictionaryValue>();
|
||||
DictionaryValue::Items &library_attributes = library_dict->elements();
|
||||
|
||||
library_attributes.append_as("name", new StringValue(library->name));
|
||||
library_attributes.append_as("path", new StringValue(library->path));
|
||||
asset_libs_elements.append_as(std::move(library_dict));
|
||||
}
|
||||
root_attributes.append_as("asset_libraries", std::move(asset_libs_array));
|
||||
}
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
@ -284,11 +354,30 @@ StringRefNull ProjectSettings::project_name() const
|
|||
return project_name_;
|
||||
}
|
||||
|
||||
const ListBase &ProjectSettings::asset_library_definitions() const
|
||||
{
|
||||
return asset_libraries_->asset_libraries;
|
||||
}
|
||||
|
||||
bool ProjectSettings::has_unsaved_changes() const
|
||||
{
|
||||
return has_unsaved_changes_;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
CustomAssetLibraries::CustomAssetLibraries(ListBase asset_libraries)
|
||||
: asset_libraries(asset_libraries)
|
||||
{
|
||||
}
|
||||
|
||||
CustomAssetLibraries::~CustomAssetLibraries()
|
||||
{
|
||||
LISTBASE_FOREACH_MUTABLE (CustomAssetLibraryDefinition *, library, &asset_libraries) {
|
||||
BKE_asset_library_custom_remove(&asset_libraries, library);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::bke
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
|
|
@ -161,12 +161,27 @@ TEST_F(ProjectTest, settings_load_from_project_settings_path)
|
|||
});
|
||||
}
|
||||
|
||||
static void project_settings_match_expected_from_svn(const ProjectSettings &project_settings)
|
||||
{
|
||||
EXPECT_EQ(project_settings.project_name(), "Ružena");
|
||||
|
||||
const ListBase &asset_libraries = project_settings.asset_library_definitions();
|
||||
CustomAssetLibraryDefinition *first = (CustomAssetLibraryDefinition *)asset_libraries.first;
|
||||
EXPECT_STREQ(first->name, "Lorem Ipsum");
|
||||
EXPECT_STREQ(first->path, "assets");
|
||||
EXPECT_EQ(first->next, asset_libraries.last);
|
||||
CustomAssetLibraryDefinition *last = (CustomAssetLibraryDefinition *)asset_libraries.last;
|
||||
EXPECT_EQ(last->prev, asset_libraries.first);
|
||||
EXPECT_STREQ(last->name, "Материалы");
|
||||
EXPECT_STREQ(last->path, "новый\\assets");
|
||||
}
|
||||
|
||||
TEST_F(ProjectTest, settings_json_read)
|
||||
{
|
||||
SVNFiles svn_files{};
|
||||
std::unique_ptr from_project_settings = ProjectSettings::load_from_disk(svn_files.project_root);
|
||||
EXPECT_NE(from_project_settings, nullptr);
|
||||
EXPECT_EQ(from_project_settings->project_name(), "Ružena");
|
||||
project_settings_match_expected_from_svn(*from_project_settings);
|
||||
}
|
||||
|
||||
TEST_F(ProjectTest, settings_json_write)
|
||||
|
@ -186,7 +201,7 @@ TEST_F(ProjectTest, settings_json_write)
|
|||
/* Now check if the settings written to disk match the expectations. */
|
||||
std::unique_ptr written_settings = ProjectSettings::load_from_disk(to_project_path);
|
||||
EXPECT_NE(written_settings, nullptr);
|
||||
EXPECT_EQ(written_settings->project_name(), "Ružena");
|
||||
project_settings_match_expected_from_svn(*written_settings);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue