diff --git a/scripts/startup/bl_ui/space_filebrowser.py b/scripts/startup/bl_ui/space_filebrowser.py index 88fdc087584..1a8063da420 100644 --- a/scripts/startup/bl_ui/space_filebrowser.py +++ b/scripts/startup/bl_ui/space_filebrowser.py @@ -745,6 +745,8 @@ class ASSETBROWSER_PT_metadata(asset_utils.AssetBrowserPanel, Panel): row.operator("asset.open_containing_blend_file", text="", icon='TOOL_SETTINGS') layout.prop(asset_file_handle.asset_data, "description") + layout.prop(asset_file_handle.asset_data, "license") + layout.prop(asset_file_handle.asset_data, "copyright") layout.prop(asset_file_handle.asset_data, "author") diff --git a/source/blender/blenkernel/intern/asset.cc b/source/blender/blenkernel/intern/asset.cc index 8fa5fc5842b..051bb3d3584 100644 --- a/source/blender/blenkernel/intern/asset.cc +++ b/source/blender/blenkernel/intern/asset.cc @@ -44,6 +44,8 @@ AssetMetaData::~AssetMetaData() } MEM_SAFE_FREE(author); MEM_SAFE_FREE(description); + MEM_SAFE_FREE(copyright); + MEM_SAFE_FREE(license); BLI_freelistN(&tags); } @@ -161,13 +163,19 @@ void BKE_asset_metadata_write(BlendWriter *writer, AssetMetaData *asset_data) if (asset_data->properties) { IDP_BlendWrite(writer, asset_data->properties); } - if (asset_data->author) { BLO_write_string(writer, asset_data->author); } if (asset_data->description) { BLO_write_string(writer, asset_data->description); } + if (asset_data->copyright) { + BLO_write_string(writer, asset_data->copyright); + } + if (asset_data->license) { + BLO_write_string(writer, asset_data->license); + } + LISTBASE_FOREACH (AssetTag *, tag, &asset_data->tags) { BLO_write_struct(writer, AssetTag, tag); } @@ -185,6 +193,8 @@ void BKE_asset_metadata_read(BlendDataReader *reader, AssetMetaData *asset_data) BLO_read_data_address(reader, &asset_data->author); BLO_read_data_address(reader, &asset_data->description); + BLO_read_data_address(reader, &asset_data->copyright); + BLO_read_data_address(reader, &asset_data->license); BLO_read_list(reader, &asset_data->tags); BLI_assert(BLI_listbase_count(&asset_data->tags) == asset_data->tot_tags); } diff --git a/source/blender/editors/asset/intern/asset_indexer.cc b/source/blender/editors/asset/intern/asset_indexer.cc index dd02e65791b..11495d4048e 100644 --- a/source/blender/editors/asset/intern/asset_indexer.cc +++ b/source/blender/editors/asset/intern/asset_indexer.cc @@ -56,13 +56,16 @@ using namespace blender::bke::idprop; * "catalog_name": "", * "description": "", * "author": "", + * "copyright": "", + * "license": "", * "tags": [""], * "properties": [..] * }] * } * \endcode * - * NOTE: entries, author, description, tags and properties are optional attributes. + * NOTE: entries, author, description, copyright, license, tags and properties are optional + * attributes. * * NOTE: File browser uses name and idcode separate. Inside the index they are joined together like * #ID.name. @@ -75,6 +78,8 @@ constexpr StringRef ATTRIBUTE_ENTRIES_CATALOG_ID("catalog_id"); constexpr StringRef ATTRIBUTE_ENTRIES_CATALOG_NAME("catalog_name"); constexpr StringRef ATTRIBUTE_ENTRIES_DESCRIPTION("description"); constexpr StringRef ATTRIBUTE_ENTRIES_AUTHOR("author"); +constexpr StringRef ATTRIBUTE_ENTRIES_COPYRIGHT("copyright"); +constexpr StringRef ATTRIBUTE_ENTRIES_LICENSE("license"); constexpr StringRef ATTRIBUTE_ENTRIES_TAGS("tags"); constexpr StringRef ATTRIBUTE_ENTRIES_PROPERTIES("properties"); @@ -178,6 +183,26 @@ struct AssetEntryReader { return lookup.lookup(ATTRIBUTE_ENTRIES_AUTHOR)->as_string_value()->value(); } + bool has_copyright() const + { + return lookup.contains(ATTRIBUTE_ENTRIES_COPYRIGHT); + } + + StringRefNull get_copyright() const + { + return lookup.lookup(ATTRIBUTE_ENTRIES_COPYRIGHT)->as_string_value()->value(); + } + + bool has_license() const + { + return lookup.contains(ATTRIBUTE_ENTRIES_LICENSE); + } + + StringRefNull get_license() const + { + return lookup.lookup(ATTRIBUTE_ENTRIES_LICENSE)->as_string_value()->value(); + } + StringRefNull get_catalog_name() const { return lookup.lookup(ATTRIBUTE_ENTRIES_CATALOG_NAME)->as_string_value()->value(); @@ -267,6 +292,16 @@ struct AssetEntryWriter { attributes.append_as(std::pair(ATTRIBUTE_ENTRIES_AUTHOR, new StringValue(author))); } + void add_copyright(const StringRefNull copyright) + { + attributes.append_as(std::pair(ATTRIBUTE_ENTRIES_COPYRIGHT, new StringValue(copyright))); + } + + void add_license(const StringRefNull license) + { + attributes.append_as(std::pair(ATTRIBUTE_ENTRIES_LICENSE, new StringValue(license))); + } + void add_tags(const ListBase /* AssetTag */ *asset_tags) { ArrayValue *tags = new ArrayValue(); @@ -305,6 +340,12 @@ static void init_value_from_file_indexer_entry(AssetEntryWriter &result, if (asset_data.author != nullptr) { result.add_author(asset_data.author); } + if (asset_data.copyright != nullptr) { + result.add_copyright(asset_data.copyright); + } + if (asset_data.license != nullptr) { + result.add_license(asset_data.license); + } if (!BLI_listbase_is_empty(&asset_data.tags)) { result.add_tags(&asset_data.tags); @@ -372,6 +413,18 @@ static void init_indexer_entry_from_value(FileIndexerEntry &indexer_entry, BLI_strncpy(author_c_str, author.c_str(), author.size() + 1); asset_data->author = author_c_str; } + if (entry.has_copyright()) { + const StringRefNull copyright = entry.get_copyright(); + char *copyright_c_str = static_cast(MEM_mallocN(copyright.size() + 1, __func__)); + BLI_strncpy(copyright_c_str, copyright.c_str(), copyright.size() + 1); + asset_data->copyright = copyright_c_str; + } + if (entry.has_license()) { + const StringRefNull license = entry.get_license(); + char *license_c_str = static_cast(MEM_mallocN(license.size() + 1, __func__)); + BLI_strncpy(license_c_str, license.c_str(), license.size() + 1); + asset_data->license = license_c_str; + } const StringRefNull catalog_name = entry.get_catalog_name(); BLI_strncpy(asset_data->catalog_simple_name, diff --git a/source/blender/makesdna/DNA_asset_types.h b/source/blender/makesdna/DNA_asset_types.h index 5ab24b2db4a..5ed625211e5 100644 --- a/source/blender/makesdna/DNA_asset_types.h +++ b/source/blender/makesdna/DNA_asset_types.h @@ -72,6 +72,12 @@ typedef struct AssetMetaData { /** Optional description of this asset for display in the UI. Dynamic length. */ char *description; + /** Optional copyright of this asset for display in the UI. Dynamic length. */ + char *copyright; + + /** Optional license of this asset for display in the UI. Dynamic length. */ + char *license; + /** User defined tags for this asset. The asset manager uses these for filtering, but how they * function exactly (e.g. how they are registered to provide a list of searchable available tags) * is up to the asset-engine. */ diff --git a/source/blender/makesrna/intern/rna_asset.c b/source/blender/makesrna/intern/rna_asset.c index b95800fe934..06de6b819ac 100644 --- a/source/blender/makesrna/intern/rna_asset.c +++ b/source/blender/makesrna/intern/rna_asset.c @@ -205,6 +205,74 @@ static void rna_AssetMetaData_description_set(PointerRNA *ptr, const char *value } } +static void rna_AssetMetaData_copyright_get(PointerRNA *ptr, char *value) +{ + AssetMetaData *asset_data = ptr->data; + + if (asset_data->copyright) { + strcpy(value, asset_data->copyright); + } + else { + value[0] = '\0'; + } +} + +static int rna_AssetMetaData_copyright_length(PointerRNA *ptr) +{ + AssetMetaData *asset_data = ptr->data; + return asset_data->copyright ? strlen(asset_data->copyright) : 0; +} + +static void rna_AssetMetaData_copyright_set(PointerRNA *ptr, const char *value) +{ + AssetMetaData *asset_data = ptr->data; + + if (asset_data->copyright) { + MEM_freeN(asset_data->copyright); + } + + if (value[0]) { + asset_data->copyright = BLI_strdup(value); + } + else { + asset_data->copyright = NULL; + } +} + +static void rna_AssetMetaData_license_get(PointerRNA *ptr, char *value) +{ + AssetMetaData *asset_data = ptr->data; + + if (asset_data->license) { + strcpy(value, asset_data->license); + } + else { + value[0] = '\0'; + } +} + +static int rna_AssetMetaData_license_length(PointerRNA *ptr) +{ + AssetMetaData *asset_data = ptr->data; + return asset_data->license ? strlen(asset_data->license) : 0; +} + +static void rna_AssetMetaData_license_set(PointerRNA *ptr, const char *value) +{ + AssetMetaData *asset_data = ptr->data; + + if (asset_data->license) { + MEM_freeN(asset_data->license); + } + + if (value[0]) { + asset_data->license = BLI_strdup(value); + } + else { + asset_data->license = NULL; + } +} + static void rna_AssetMetaData_active_tag_range( PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax) { @@ -397,6 +465,30 @@ static void rna_def_asset_data(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Description", "A description of the asset to be displayed for the user"); + prop = RNA_def_property(srna, "copyright", PROP_STRING, PROP_NONE); + RNA_def_property_editable_func(prop, "rna_AssetMetaData_editable"); + RNA_def_property_string_funcs(prop, + "rna_AssetMetaData_copyright_get", + "rna_AssetMetaData_copyright_length", + "rna_AssetMetaData_copyright_set"); + RNA_def_property_ui_text( + prop, + "Copyright", + "Copyright notice for this asset. An empty copyright notice does not necessarily indicate " + "that this is copyright-free. Contact the author if any clarification is needed"); + + prop = RNA_def_property(srna, "license", PROP_STRING, PROP_NONE); + RNA_def_property_editable_func(prop, "rna_AssetMetaData_editable"); + RNA_def_property_string_funcs(prop, + "rna_AssetMetaData_license_get", + "rna_AssetMetaData_license_length", + "rna_AssetMetaData_license_set"); + RNA_def_property_ui_text(prop, + "License", + "The type of license this asset is distributed under. An empty license " + "name does not necessarily indicate that this is free of licensing " + "terms. Contact the author if any clarification is needed"); + prop = RNA_def_property(srna, "tags", PROP_COLLECTION, PROP_NONE); RNA_def_property_struct_type(prop, "AssetTag"); RNA_def_property_editable_func(prop, "rna_AssetMetaData_editable");