WIP: Brush assets project #106303
|
@ -52,6 +52,7 @@ class VIEW3D_MT_brush_context_menu(Menu):
|
||||||
|
|
||||||
layout.separator()
|
layout.separator()
|
||||||
|
|
||||||
|
layout.operator("brush.asset_edit_metadata", text="Edit Metadata")
|
||||||
layout.operator("brush.asset_update", text="Update Asset")
|
layout.operator("brush.asset_update", text="Update Asset")
|
||||||
layout.operator("brush.asset_revert", text="Revert to Asset")
|
layout.operator("brush.asset_revert", text="Revert to Asset")
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#include "DNA_ID_enums.h"
|
#include "DNA_ID_enums.h"
|
||||||
|
|
||||||
struct bUserAssetLibrary;
|
struct bUserAssetLibrary;
|
||||||
|
struct AssetMetaData;
|
||||||
struct AssetWeakReference;
|
struct AssetWeakReference;
|
||||||
struct ID;
|
struct ID;
|
||||||
struct Main;
|
struct Main;
|
||||||
|
@ -52,14 +53,11 @@ Main *asset_edit_main(const ID &id);
|
||||||
|
|
||||||
bool asset_edit_id_is_editable(const ID &id);
|
bool asset_edit_id_is_editable(const ID &id);
|
||||||
|
|
||||||
std::optional<std::string> asset_edit_id_save_as(
|
std::optional<std::string> asset_edit_id_save_as(Main &global_main,
|
||||||
Main &global_main,
|
const ID &id,
|
||||||
const ID &id,
|
StringRef name,
|
||||||
StringRef name,
|
const bUserAssetLibrary &user_library,
|
||||||
std::optional<blender::asset_system::CatalogID> catalog_id,
|
ReportList &reports);
|
||||||
std::optional<std::string> catalog_simple_name,
|
|
||||||
const bUserAssetLibrary &user_library,
|
|
||||||
ReportList &reports);
|
|
||||||
|
|
||||||
bool asset_edit_id_save(Main &global_main, const ID &id, ReportList &reports);
|
bool asset_edit_id_save(Main &global_main, const ID &id, ReportList &reports);
|
||||||
bool asset_edit_id_revert(Main &global_main, const ID &id, ReportList &reports);
|
bool asset_edit_id_revert(Main &global_main, const ID &id, ReportList &reports);
|
||||||
|
|
|
@ -194,12 +194,11 @@ static bool asset_write_in_library(Main *bmain,
|
||||||
const ID &id_const,
|
const ID &id_const,
|
||||||
const StringRef name,
|
const StringRef name,
|
||||||
const StringRefNull filepath,
|
const StringRefNull filepath,
|
||||||
const std::optional<asset_system::CatalogID> catalog,
|
|
||||||
const std::optional<StringRefNull> catalog_simple_name,
|
|
||||||
std::string &final_full_file_path,
|
std::string &final_full_file_path,
|
||||||
ReportList &reports)
|
ReportList &reports)
|
||||||
{
|
{
|
||||||
/* XXX
|
/* TODO: Comment seems to be resolved by separate #Main storage?
|
||||||
|
* XXX
|
||||||
* FIXME
|
* FIXME
|
||||||
*
|
*
|
||||||
* This code is _pure evil_. It does in-place manipulation on IDs in global Main database,
|
* This code is _pure evil_. It does in-place manipulation on IDs in global Main database,
|
||||||
|
@ -224,8 +223,8 @@ static bool asset_write_in_library(Main *bmain,
|
||||||
const int prev_tag = id.tag;
|
const int prev_tag = id.tag;
|
||||||
const int prev_us = id.us;
|
const int prev_us = id.us;
|
||||||
const std::string prev_name = id.name + 2;
|
const std::string prev_name = id.name + 2;
|
||||||
|
/* TODO: Remove library overrides stuff now that they are not used for brush assets. */
|
||||||
IDOverrideLibrary *prev_liboverride = id.override_library;
|
IDOverrideLibrary *prev_liboverride = id.override_library;
|
||||||
AssetMetaData *asset_data = id.asset_data;
|
|
||||||
const int write_flags = 0; /* Could use #G_FILE_COMPRESS ? */
|
const int write_flags = 0; /* Could use #G_FILE_COMPRESS ? */
|
||||||
const eBLO_WritePathRemap remap_mode = BLO_WRITE_PATH_REMAP_RELATIVE;
|
const eBLO_WritePathRemap remap_mode = BLO_WRITE_PATH_REMAP_RELATIVE;
|
||||||
|
|
||||||
|
@ -235,18 +234,8 @@ static bool asset_write_in_library(Main *bmain,
|
||||||
id.tag &= ~LIB_TAG_RUNTIME;
|
id.tag &= ~LIB_TAG_RUNTIME;
|
||||||
id.us = 1;
|
id.us = 1;
|
||||||
BLI_strncpy(id.name + 2, name.data(), std::min(sizeof(id.name) - 2, size_t(name.size())));
|
BLI_strncpy(id.name + 2, name.data(), std::min(sizeof(id.name) - 2, size_t(name.size())));
|
||||||
if (!ID_IS_ASSET(&id)) {
|
|
||||||
id.asset_data = id.override_library->reference->asset_data;
|
|
||||||
}
|
|
||||||
id.override_library = nullptr;
|
id.override_library = nullptr;
|
||||||
|
|
||||||
if (catalog) {
|
|
||||||
id.asset_data->catalog_id = *catalog;
|
|
||||||
}
|
|
||||||
if (catalog_simple_name) {
|
|
||||||
STRNCPY(id.asset_data->catalog_simple_name, catalog_simple_name->c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
BKE_blendfile_write_partial_tag_ID(&id, true);
|
BKE_blendfile_write_partial_tag_ID(&id, true);
|
||||||
|
|
||||||
/* TODO: check overwriting existing file. */
|
/* TODO: check overwriting existing file. */
|
||||||
|
@ -266,7 +255,6 @@ static bool asset_write_in_library(Main *bmain,
|
||||||
id.us = prev_us;
|
id.us = prev_us;
|
||||||
BLI_strncpy(id.name + 2, prev_name.c_str(), sizeof(id.name) - 2);
|
BLI_strncpy(id.name + 2, prev_name.c_str(), sizeof(id.name) - 2);
|
||||||
id.override_library = prev_liboverride;
|
id.override_library = prev_liboverride;
|
||||||
id.asset_data = asset_data;
|
|
||||||
|
|
||||||
return sucess;
|
return sucess;
|
||||||
}
|
}
|
||||||
|
@ -379,8 +367,6 @@ static AssetEditBlend &asset_edit_blend_file_ensure(const StringRef filepath)
|
||||||
std::optional<std::string> asset_edit_id_save_as(Main &global_main,
|
std::optional<std::string> asset_edit_id_save_as(Main &global_main,
|
||||||
const ID &id,
|
const ID &id,
|
||||||
const StringRef name,
|
const StringRef name,
|
||||||
std::optional<asset_system::CatalogID> catalog_id,
|
|
||||||
std::optional<std::string> catalog_simple_name,
|
|
||||||
const bUserAssetLibrary &user_library,
|
const bUserAssetLibrary &user_library,
|
||||||
ReportList &reports)
|
ReportList &reports)
|
||||||
{
|
{
|
||||||
|
@ -391,14 +377,8 @@ std::optional<std::string> asset_edit_id_save_as(Main &global_main,
|
||||||
Main *asset_main = BKE_main_from_id(&global_main, &id);
|
Main *asset_main = BKE_main_from_id(&global_main, &id);
|
||||||
|
|
||||||
std::string final_full_asset_filepath;
|
std::string final_full_asset_filepath;
|
||||||
const bool success = asset_write_in_library(asset_main,
|
const bool success = asset_write_in_library(
|
||||||
id,
|
asset_main, id, name, filepath, final_full_asset_filepath, reports);
|
||||||
name,
|
|
||||||
filepath,
|
|
||||||
catalog_id,
|
|
||||||
catalog_simple_name,
|
|
||||||
final_full_asset_filepath,
|
|
||||||
reports);
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
BKE_report(&reports, RPT_ERROR, "Failed to write to asset library");
|
BKE_report(&reports, RPT_ERROR, "Failed to write to asset library");
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
|
@ -421,8 +401,6 @@ bool asset_edit_id_save(Main & /*global_main*/, const ID &id, ReportList &report
|
||||||
id,
|
id,
|
||||||
id.name + 2,
|
id.name + 2,
|
||||||
asset_blend->filepath.c_str(),
|
asset_blend->filepath.c_str(),
|
||||||
std::nullopt,
|
|
||||||
std::nullopt,
|
|
||||||
final_full_asset_filepath,
|
final_full_asset_filepath,
|
||||||
reports);
|
reports);
|
||||||
|
|
||||||
|
|
|
@ -788,23 +788,49 @@ static AssetWeakReference brush_asset_create_weakref_hack(const bUserAssetLibrar
|
||||||
return asset_weak_ref;
|
return asset_weak_ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void refresh_asset_library(const bContext *C, const bUserAssetLibrary &user_library)
|
static std::optional<AssetLibraryReference> library_to_library_ref(
|
||||||
|
const asset_system::AssetLibrary &library)
|
||||||
{
|
{
|
||||||
|
for (const AssetLibraryReference &ref : asset_system::all_valid_asset_library_refs()) {
|
||||||
|
const std::string root_path = AS_asset_library_root_path_from_library_ref(ref);
|
||||||
|
/* Use #BLI_path_cmp_normalized because `library.root_path()` ends with a slash while
|
||||||
|
* `root_path` doesn't. */
|
||||||
|
if (BLI_path_cmp_normalized(root_path.c_str(), library.root_path().c_str()) == 0) {
|
||||||
|
return ref;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
static AssetLibraryReference user_library_to_library_ref(const bUserAssetLibrary &user_library)
|
||||||
|
{
|
||||||
|
AssetLibraryReference library_ref{};
|
||||||
|
library_ref.custom_library_index = BLI_findindex(&U.asset_libraries, &user_library);
|
||||||
|
library_ref.type = ASSET_LIBRARY_CUSTOM;
|
||||||
|
return library_ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const bUserAssetLibrary *library_ref_to_user_library(
|
||||||
|
const AssetLibraryReference &library_ref)
|
||||||
|
{
|
||||||
|
if (library_ref.type != ASSET_LIBRARY_CUSTOM) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return static_cast<const bUserAssetLibrary *>(
|
||||||
|
BLI_findlink(&U.asset_libraries, library_ref.custom_library_index));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void refresh_asset_library(const bContext *C, const AssetLibraryReference &library_ref)
|
||||||
|
{
|
||||||
|
asset::list::clear(&library_ref, C);
|
||||||
/* TODO: Should the all library reference be automatically cleared? */
|
/* TODO: Should the all library reference be automatically cleared? */
|
||||||
AssetLibraryReference all_lib_ref = asset_system::all_library_reference();
|
AssetLibraryReference all_lib_ref = asset_system::all_library_reference();
|
||||||
asset::list::clear(&all_lib_ref, C);
|
asset::list::clear(&all_lib_ref, C);
|
||||||
|
}
|
||||||
|
|
||||||
/* TODO: this is convoluted, can we create a reference from pointer? */
|
static void refresh_asset_library(const bContext *C, const bUserAssetLibrary &user_library)
|
||||||
for (const AssetLibraryReference &lib_ref : asset_system::all_valid_asset_library_refs()) {
|
{
|
||||||
if (lib_ref.type == ASSET_LIBRARY_CUSTOM) {
|
refresh_asset_library(C, user_library_to_library_ref(user_library));
|
||||||
const bUserAssetLibrary *ref_user_library = BKE_preferences_asset_library_find_index(
|
|
||||||
&U, lib_ref.custom_library_index);
|
|
||||||
if (ref_user_library == &user_library) {
|
|
||||||
asset::list::clear(&lib_ref, C);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool brush_asset_save_as_poll(bContext *C)
|
static bool brush_asset_save_as_poll(bContext *C)
|
||||||
|
@ -858,14 +884,6 @@ static asset_system::AssetCatalog &asset_library_ensure_catalogs_in_path(
|
||||||
return *library.catalog_service().find_catalog_by_path(path);
|
return *library.catalog_service().find_catalog_by_path(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
static AssetLibraryReference user_library_to_library_ref(const bUserAssetLibrary &user_library)
|
|
||||||
{
|
|
||||||
AssetLibraryReference library_ref{};
|
|
||||||
library_ref.custom_library_index = BLI_findindex(&U.asset_libraries, &user_library);
|
|
||||||
library_ref.type = ASSET_LIBRARY_CUSTOM;
|
|
||||||
return library_ref;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int brush_asset_save_as_exec(bContext *C, wmOperator *op)
|
static int brush_asset_save_as_exec(bContext *C, wmOperator *op)
|
||||||
{
|
{
|
||||||
Main *bmain = CTX_data_main(C);
|
Main *bmain = CTX_data_main(C);
|
||||||
|
@ -905,19 +923,15 @@ static int brush_asset_save_as_exec(bContext *C, wmOperator *op)
|
||||||
char catalog_path[MAX_NAME];
|
char catalog_path[MAX_NAME];
|
||||||
RNA_string_get(op->ptr, "catalog_path", catalog_path);
|
RNA_string_get(op->ptr, "catalog_path", catalog_path);
|
||||||
|
|
||||||
std::optional<asset_system::CatalogID> catalog_id;
|
AssetMetaData &meta_data = *brush->id.asset_data;
|
||||||
std::optional<StringRefNull> catalog_simple_name;
|
|
||||||
|
|
||||||
if (catalog_path[0]) {
|
if (catalog_path[0]) {
|
||||||
const asset_system::AssetCatalog &catalog = asset_library_ensure_catalogs_in_path(
|
const asset_system::AssetCatalog &catalog = asset_library_ensure_catalogs_in_path(
|
||||||
*library, catalog_path);
|
*library, catalog_path);
|
||||||
catalog_id = catalog.catalog_id;
|
BKE_asset_metadata_catalog_id_set(&meta_data, catalog.catalog_id, catalog.simple_name.c_str());
|
||||||
catalog_simple_name = catalog.simple_name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::optional<std::string> final_full_asset_filepath = bke::asset_edit_id_save_as(
|
const std::optional<std::string> final_full_asset_filepath = bke::asset_edit_id_save_as(
|
||||||
*bmain, brush->id, name, catalog_id, catalog_simple_name, *user_library, *op->reports);
|
*bmain, brush->id, name, *user_library, *op->reports);
|
||||||
|
|
||||||
if (!final_full_asset_filepath) {
|
if (!final_full_asset_filepath) {
|
||||||
return OPERATOR_CANCELLED;
|
return OPERATOR_CANCELLED;
|
||||||
}
|
}
|
||||||
|
@ -942,20 +956,6 @@ static int brush_asset_save_as_exec(bContext *C, wmOperator *op)
|
||||||
return OPERATOR_FINISHED;
|
return OPERATOR_FINISHED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::optional<AssetLibraryReference> library_to_library_ref(
|
|
||||||
const asset_system::AssetLibrary &library)
|
|
||||||
{
|
|
||||||
for (const AssetLibraryReference &ref : asset_system::all_valid_asset_library_refs()) {
|
|
||||||
const std::string root_path = AS_asset_library_root_path_from_library_ref(ref);
|
|
||||||
/* Use #BLI_path_cmp_normalized because `library.root_path()` ends with a slash while
|
|
||||||
* `root_path` doesn't. */
|
|
||||||
if (BLI_path_cmp_normalized(root_path.c_str(), library.root_path().c_str()) == 0) {
|
|
||||||
return ref;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool library_is_editable(const AssetLibraryReference &library)
|
static bool library_is_editable(const AssetLibraryReference &library)
|
||||||
{
|
{
|
||||||
if (library.type == ASSET_LIBRARY_ESSENTIALS) {
|
if (library.type == ASSET_LIBRARY_ESSENTIALS) {
|
||||||
|
@ -967,12 +967,10 @@ static bool library_is_editable(const AssetLibraryReference &library)
|
||||||
static int brush_asset_save_as_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
|
static int brush_asset_save_as_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
|
||||||
{
|
{
|
||||||
Paint *paint = BKE_paint_get_active_from_context(C);
|
Paint *paint = BKE_paint_get_active_from_context(C);
|
||||||
Brush *brush = BKE_paint_brush(paint);
|
|
||||||
const AssetWeakReference &brush_weak_ref = *paint->brush_asset_reference;
|
const AssetWeakReference &brush_weak_ref = *paint->brush_asset_reference;
|
||||||
const asset_system::AssetRepresentation *asset = asset::find_asset_from_weak_ref(
|
const asset_system::AssetRepresentation *asset = asset::find_asset_from_weak_ref(
|
||||||
*C, brush_weak_ref, op->reports);
|
*C, brush_weak_ref, op->reports);
|
||||||
if (!asset) {
|
if (!asset) {
|
||||||
BLI_assert_unreachable();
|
|
||||||
return OPERATOR_CANCELLED;
|
return OPERATOR_CANCELLED;
|
||||||
}
|
}
|
||||||
const asset_system::AssetLibrary &library = asset->owner_asset_library();
|
const asset_system::AssetLibrary &library = asset->owner_asset_library();
|
||||||
|
@ -982,7 +980,7 @@ static int brush_asset_save_as_invoke(bContext *C, wmOperator *op, const wmEvent
|
||||||
return OPERATOR_CANCELLED;
|
return OPERATOR_CANCELLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
RNA_string_set(op->ptr, "name", brush->id.name + 2);
|
RNA_string_set(op->ptr, "name", asset->get_name().c_str());
|
||||||
|
|
||||||
/* If the library isn't saved from the operator's last execution, find the current library or the
|
/* If the library isn't saved from the operator's last execution, find the current library or the
|
||||||
* first library if the current library isn't editable. */
|
* first library if the current library isn't editable. */
|
||||||
|
@ -1027,27 +1025,20 @@ static const EnumPropertyItem *rna_asset_library_reference_itemf(bContext * /*C*
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void visit_asset_catalog_for_search_fn(
|
static void visit_library_catalogs_catalog_for_search(
|
||||||
const bContext *C,
|
const Main &bmain,
|
||||||
PointerRNA *ptr,
|
const bUserAssetLibrary &user_library,
|
||||||
PropertyRNA * /*prop*/,
|
const StringRef edit_text,
|
||||||
const char *edit_text,
|
const FunctionRef<void(StringPropertySearchVisitParams)> visit_fn)
|
||||||
FunctionRef<void(StringPropertySearchVisitParams)> visit_fn)
|
|
||||||
{
|
{
|
||||||
/* NOTE: Using the all library would also be a valid choice. */
|
const asset_system::AssetLibrary *library = AS_asset_library_load(
|
||||||
const bUserAssetLibrary *user_library = get_asset_library_from_prop(*ptr);
|
&bmain, user_library_to_library_ref(user_library));
|
||||||
if (!user_library) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
asset_system::AssetLibrary *library = AS_asset_library_load(
|
|
||||||
CTX_data_main(C), user_library_to_library_ref(*user_library));
|
|
||||||
if (!library) {
|
if (!library) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (edit_text && edit_text[0] != '\0') {
|
if (!edit_text.is_empty()) {
|
||||||
asset_system::AssetCatalogPath edit_path = edit_text;
|
const asset_system::AssetCatalogPath edit_path = edit_text;
|
||||||
if (!library->catalog_service().find_catalog_by_path(edit_path)) {
|
if (!library->catalog_service().find_catalog_by_path(edit_path)) {
|
||||||
visit_fn(StringPropertySearchVisitParams{edit_path.str(), std::nullopt, ICON_ADD});
|
visit_fn(StringPropertySearchVisitParams{edit_path.str(), std::nullopt, ICON_ADD});
|
||||||
}
|
}
|
||||||
|
@ -1059,6 +1050,20 @@ static void visit_asset_catalog_for_search_fn(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void visit_library_prop_catalogs_catalog_for_search_fn(
|
||||||
|
const bContext *C,
|
||||||
|
PointerRNA *ptr,
|
||||||
|
PropertyRNA * /*prop*/,
|
||||||
|
const char *edit_text,
|
||||||
|
FunctionRef<void(StringPropertySearchVisitParams)> visit_fn)
|
||||||
|
{
|
||||||
|
/* NOTE: Using the all library would also be a valid choice. */
|
||||||
|
if (const bUserAssetLibrary *user_library = get_asset_library_from_prop(*ptr)) {
|
||||||
|
visit_library_catalogs_catalog_for_search(
|
||||||
|
*CTX_data_main(C), *user_library, edit_text, visit_fn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void BRUSH_OT_asset_save_as(wmOperatorType *ot)
|
static void BRUSH_OT_asset_save_as(wmOperatorType *ot)
|
||||||
{
|
{
|
||||||
ot->name = "Save as Brush Asset";
|
ot->name = "Save as Brush Asset";
|
||||||
|
@ -1081,7 +1086,168 @@ static void BRUSH_OT_asset_save_as(wmOperatorType *ot)
|
||||||
prop = RNA_def_string(
|
prop = RNA_def_string(
|
||||||
ot->srna, "catalog_path", nullptr, MAX_NAME, "Catalog", "Catalog to use for the new asset");
|
ot->srna, "catalog_path", nullptr, MAX_NAME, "Catalog", "Catalog to use for the new asset");
|
||||||
RNA_def_property_string_search_func_runtime(
|
RNA_def_property_string_search_func_runtime(
|
||||||
prop, visit_asset_catalog_for_search_fn, PROP_STRING_SEARCH_SUGGESTION);
|
prop, visit_library_prop_catalogs_catalog_for_search_fn, PROP_STRING_SEARCH_SUGGESTION);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int brush_asset_edit_metadata_exec(bContext *C, wmOperator *op)
|
||||||
|
{
|
||||||
|
Main *bmain = CTX_data_main(C);
|
||||||
|
const Paint *paint = BKE_paint_get_active_from_context(C);
|
||||||
|
const Brush *brush = (paint) ? BKE_paint_brush_for_read(paint) : nullptr;
|
||||||
|
BLI_assert(ID_IS_ASSET(&brush->id));
|
||||||
|
const AssetWeakReference &brush_weak_ref = *paint->brush_asset_reference;
|
||||||
|
const asset_system::AssetRepresentation *asset = asset::find_asset_from_weak_ref(
|
||||||
|
*C, brush_weak_ref, op->reports);
|
||||||
|
if (!asset) {
|
||||||
|
return OPERATOR_CANCELLED;
|
||||||
|
}
|
||||||
|
const asset_system::AssetLibrary &library_const = asset->owner_asset_library();
|
||||||
|
const AssetLibraryReference library_ref = *library_to_library_ref(library_const);
|
||||||
|
asset_system::AssetLibrary *library = AS_asset_library_load(bmain, library_ref);
|
||||||
|
|
||||||
|
char catalog_path[MAX_NAME];
|
||||||
|
RNA_string_get(op->ptr, "catalog_path", catalog_path);
|
||||||
|
|
||||||
|
AssetMetaData &meta_data = *brush->id.asset_data;
|
||||||
|
MEM_SAFE_FREE(meta_data.author);
|
||||||
|
meta_data.author = RNA_string_get_alloc(op->ptr, "author", nullptr, 0, nullptr);
|
||||||
|
MEM_SAFE_FREE(meta_data.description);
|
||||||
|
meta_data.description = RNA_string_get_alloc(op->ptr, "description", nullptr, 0, nullptr);
|
||||||
|
|
||||||
|
if (catalog_path[0]) {
|
||||||
|
const asset_system::AssetCatalog &catalog = asset_library_ensure_catalogs_in_path(
|
||||||
|
*library, catalog_path);
|
||||||
|
BKE_asset_metadata_catalog_id_set(&meta_data, catalog.catalog_id, catalog.simple_name.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bke::asset_edit_id_save(*bmain, brush->id, *op->reports)) {
|
||||||
|
return OPERATOR_CANCELLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
char asset_full_path_buffer[FILE_MAX_LIBEXTRA];
|
||||||
|
char *file_path = nullptr;
|
||||||
|
AS_asset_full_path_explode_from_weak_ref(
|
||||||
|
&brush_weak_ref, asset_full_path_buffer, &file_path, nullptr, nullptr);
|
||||||
|
if (!file_path) {
|
||||||
|
BLI_assert_unreachable();
|
||||||
|
return OPERATOR_CANCELLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
library->catalog_service().write_to_disk(file_path);
|
||||||
|
|
||||||
|
refresh_asset_library(C, library_ref);
|
||||||
|
WM_main_add_notifier(NC_ASSET | ND_ASSET_LIST | NA_EDITED, nullptr);
|
||||||
|
|
||||||
|
return OPERATOR_FINISHED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int brush_asset_edit_metadata_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
|
||||||
|
{
|
||||||
|
const Paint *paint = BKE_paint_get_active_from_context(C);
|
||||||
|
const AssetWeakReference &brush_weak_ref = *paint->brush_asset_reference;
|
||||||
|
const asset_system::AssetRepresentation *asset = asset::find_asset_from_weak_ref(
|
||||||
|
*C, brush_weak_ref, op->reports);
|
||||||
|
if (!asset) {
|
||||||
|
return OPERATOR_CANCELLED;
|
||||||
|
}
|
||||||
|
const asset_system::AssetLibrary &library = asset->owner_asset_library();
|
||||||
|
const AssetMetaData &meta_data = asset->get_metadata();
|
||||||
|
|
||||||
|
if (!RNA_struct_property_is_set(op->ptr, "catalog_path")) {
|
||||||
|
const asset_system::CatalogID &id = meta_data.catalog_id;
|
||||||
|
if (const asset_system::AssetCatalog *catalog = library.catalog_service().find_catalog(id)) {
|
||||||
|
RNA_string_set(op->ptr, "catalog_path", catalog->path.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!RNA_struct_property_is_set(op->ptr, "author")) {
|
||||||
|
RNA_string_set(op->ptr, "author", meta_data.author ? meta_data.author : "");
|
||||||
|
}
|
||||||
|
if (!RNA_struct_property_is_set(op->ptr, "description")) {
|
||||||
|
RNA_string_set(op->ptr, "description", meta_data.description ? meta_data.description : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
return WM_operator_props_dialog_popup(C, op, 400, std::nullopt, IFACE_("Edit Metadata"));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void visit_active_library_catalogs_catalog_for_search_fn(
|
||||||
|
const bContext *C,
|
||||||
|
PointerRNA * /*ptr*/,
|
||||||
|
PropertyRNA * /*prop*/,
|
||||||
|
const char *edit_text,
|
||||||
|
FunctionRef<void(StringPropertySearchVisitParams)> visit_fn)
|
||||||
|
{
|
||||||
|
const Paint *paint = BKE_paint_get_active_from_context(C);
|
||||||
|
const AssetWeakReference &brush_weak_ref = *paint->brush_asset_reference;
|
||||||
|
const asset_system::AssetRepresentation *asset = asset::find_asset_from_weak_ref(
|
||||||
|
*C, brush_weak_ref, nullptr);
|
||||||
|
if (!asset) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const asset_system::AssetLibrary &library = asset->owner_asset_library();
|
||||||
|
|
||||||
|
/* NOTE: Using the all library would also be a valid choice. */
|
||||||
|
visit_library_catalogs_catalog_for_search(
|
||||||
|
*CTX_data_main(C),
|
||||||
|
*library_ref_to_user_library(*library_to_library_ref(library)),
|
||||||
|
edit_text,
|
||||||
|
visit_fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool brush_asset_edit_metadata_poll(bContext *C)
|
||||||
|
{
|
||||||
|
Paint *paint = BKE_paint_get_active_from_context(C);
|
||||||
|
Brush *brush = (paint) ? BKE_paint_brush(paint) : nullptr;
|
||||||
|
if (paint == nullptr || brush == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!ID_IS_ASSET(&brush->id)) {
|
||||||
|
BLI_assert_unreachable();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const AssetWeakReference *brush_weak_ref = paint->brush_asset_reference;
|
||||||
|
if (!brush_weak_ref) {
|
||||||
|
BLI_assert_unreachable();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const asset_system::AssetRepresentation *asset = asset::find_asset_from_weak_ref(
|
||||||
|
*C, *brush_weak_ref, nullptr);
|
||||||
|
if (!asset) {
|
||||||
|
BLI_assert_unreachable();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const std::optional<AssetLibraryReference> library_ref = library_to_library_ref(
|
||||||
|
asset->owner_asset_library());
|
||||||
|
if (!library_ref) {
|
||||||
|
BLI_assert_unreachable();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!library_is_editable(*library_ref)) {
|
||||||
|
CTX_wm_operator_poll_msg_set(C, "Asset library is not editable");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!bke::asset_edit_id_is_editable(brush->id)) {
|
||||||
|
CTX_wm_operator_poll_msg_set(C, "Asset file is not editable");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void BRUSH_OT_asset_edit_metadata(wmOperatorType *ot)
|
||||||
|
{
|
||||||
|
ot->name = "Edit Metadata";
|
||||||
|
ot->description = "Edit asset information like the catalog, preview image, tags, or author";
|
||||||
|
ot->idname = "BRUSH_OT_asset_edit_metadata";
|
||||||
|
|
||||||
|
ot->exec = brush_asset_edit_metadata_exec;
|
||||||
|
ot->invoke = brush_asset_edit_metadata_invoke;
|
||||||
|
ot->poll = brush_asset_edit_metadata_poll;
|
||||||
|
|
||||||
|
PropertyRNA *prop = RNA_def_string(
|
||||||
|
ot->srna, "catalog_path", nullptr, MAX_NAME, "Catalog", "The asset's catalog path");
|
||||||
|
RNA_def_property_string_search_func_runtime(
|
||||||
|
prop, visit_active_library_catalogs_catalog_for_search_fn, PROP_STRING_SEARCH_SUGGESTION);
|
||||||
|
RNA_def_string(ot->srna, "author", nullptr, MAX_NAME, "Author", "");
|
||||||
|
RNA_def_string(ot->srna, "description", nullptr, MAX_NAME, "Description", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool brush_asset_delete_poll(bContext *C)
|
static bool brush_asset_delete_poll(bContext *C)
|
||||||
|
@ -1710,6 +1876,7 @@ void ED_operatortypes_paint()
|
||||||
WM_operatortype_append(BRUSH_OT_stencil_reset_transform);
|
WM_operatortype_append(BRUSH_OT_stencil_reset_transform);
|
||||||
WM_operatortype_append(BRUSH_OT_asset_select);
|
WM_operatortype_append(BRUSH_OT_asset_select);
|
||||||
WM_operatortype_append(BRUSH_OT_asset_save_as);
|
WM_operatortype_append(BRUSH_OT_asset_save_as);
|
||||||
|
WM_operatortype_append(BRUSH_OT_asset_edit_metadata);
|
||||||
WM_operatortype_append(BRUSH_OT_asset_delete);
|
WM_operatortype_append(BRUSH_OT_asset_delete);
|
||||||
WM_operatortype_append(BRUSH_OT_asset_update);
|
WM_operatortype_append(BRUSH_OT_asset_update);
|
||||||
WM_operatortype_append(BRUSH_OT_asset_revert);
|
WM_operatortype_append(BRUSH_OT_asset_revert);
|
||||||
|
|
Loading…
Reference in New Issue