From 65591b2c8cc83b024bc0a283bae1bbeb7ee85132 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Tue, 1 Aug 2023 14:54:58 +0200 Subject: [PATCH] Refactor: Retrieve node operator asset with property In order to more reliably pass the asset to the operator, use a string property with the full asset path instead of using a context pointer. This is required to support the quick favorites menu, shortcuts, and to draw operator inputs in the redo panel. In all of those situations the original context isn't available. This also feels safer, since we rely less on storing pointers to data with a less-defined lifetime. Pull Request: https://projects.blender.org/blender/blender/pulls/110018 --- .../blender/asset_system/AS_asset_library.hh | 2 + .../asset_system/intern/asset_library.cc | 7 + .../editors/geometry/node_group_operator.cc | 151 ++++++++++++++---- source/blender/makesrna/RNA_enum_items.h | 2 + source/blender/makesrna/intern/rna_asset.cc | 8 + 5 files changed, 142 insertions(+), 28 deletions(-) diff --git a/source/blender/asset_system/AS_asset_library.hh b/source/blender/asset_system/AS_asset_library.hh index aaf33d1d6b6..442b1d96bdc 100644 --- a/source/blender/asset_system/AS_asset_library.hh +++ b/source/blender/asset_system/AS_asset_library.hh @@ -166,6 +166,8 @@ class AssetLibrary { */ AssetIdentifier asset_identifier_from_library(StringRef relative_asset_path); + std::string resolve_asset_weak_reference_to_full_path(const AssetWeakReference &asset_reference); + eAssetLibraryType library_type() const; StringRefNull name() const; StringRefNull root_path() const; diff --git a/source/blender/asset_system/intern/asset_library.cc b/source/blender/asset_system/intern/asset_library.cc index 3c8e16b5c60..541bc2932d3 100644 --- a/source/blender/asset_system/intern/asset_library.cc +++ b/source/blender/asset_system/intern/asset_library.cc @@ -302,6 +302,13 @@ AssetIdentifier AssetLibrary::asset_identifier_from_library(StringRef relative_a return AssetIdentifier(root_path_, relative_asset_path); } +std::string AssetLibrary::resolve_asset_weak_reference_to_full_path( + const AssetWeakReference &asset_reference) +{ + AssetLibraryService *service = AssetLibraryService::get(); + return service->resolve_asset_weak_reference_to_full_path(asset_reference); +} + void AssetLibrary::refresh_catalog_simplename(AssetMetaData *asset_data) { if (BLI_uuid_is_nil(asset_data->catalog_id)) { diff --git a/source/blender/editors/geometry/node_group_operator.cc b/source/blender/editors/geometry/node_group_operator.cc index f8d9a76008b..40c9d263f12 100644 --- a/source/blender/editors/geometry/node_group_operator.cc +++ b/source/blender/editors/geometry/node_group_operator.cc @@ -39,6 +39,7 @@ #include "DEG_depsgraph_query.h" #include "RNA_access.h" +#include "RNA_define.h" #include "RNA_enum_types.h" #include "UI_interface.h" @@ -69,9 +70,92 @@ namespace blender::ed::geometry { /** \name Operator * \{ */ -static const bNodeTree *get_node_group(const bContext &C) +/** + * #AssetLibrary::resolve_asset_weak_reference_to_full_path() currently does not support local + * assets. + */ +static const asset_system::AssetRepresentation *get_local_asset_from_relative_identifier( + const bContext &C, const StringRefNull relative_identifier, ReportList *reports) { - const asset_system::AssetRepresentation *asset = CTX_wm_asset(&C); + AssetLibraryReference library_ref{}; + library_ref.type = ASSET_LIBRARY_LOCAL; + ED_assetlist_storage_fetch(&library_ref, &C); + ED_assetlist_ensure_previews_job(&library_ref, &C); + + const asset_system::AssetRepresentation *matching_asset = nullptr; + ED_assetlist_iterate(library_ref, [&](asset_system::AssetRepresentation &asset) { + if (asset.get_identifier().library_relative_identifier() == relative_identifier) { + matching_asset = &asset; + return false; + } + return true; + }); + + if (reports && !matching_asset) { + if (ED_assetlist_is_loaded(&library_ref)) { + BKE_reportf( + reports, RPT_ERROR, "No asset found at path \"%s\"", relative_identifier.c_str()); + } + else { + BKE_report(reports, RPT_WARNING, "Asset loading is unfinished"); + } + } + return matching_asset; +} + +static const asset_system::AssetRepresentation *find_asset_from_weak_ref( + const bContext &C, const AssetWeakReference &weak_ref, ReportList *reports) +{ + if (weak_ref.asset_library_type == ASSET_LIBRARY_LOCAL) { + return get_local_asset_from_relative_identifier( + C, weak_ref.relative_asset_identifier, reports); + } + + const AssetLibraryReference library_ref = asset_system::all_library_reference(); + ED_assetlist_storage_fetch(&library_ref, &C); + ED_assetlist_ensure_previews_job(&library_ref, &C); + asset_system::AssetLibrary *all_library = ED_assetlist_library_get_once_available( + asset_system::all_library_reference()); + if (!all_library) { + BKE_report(reports, RPT_WARNING, "Asset loading is unfinished"); + } + + const std::string full_path = all_library->resolve_asset_weak_reference_to_full_path(weak_ref); + + const asset_system::AssetRepresentation *matching_asset = nullptr; + ED_assetlist_iterate(library_ref, [&](asset_system::AssetRepresentation &asset) { + if (asset.get_identifier().full_path() == full_path) { + matching_asset = &asset; + return false; + } + return true; + }); + + if (reports && !matching_asset) { + if (ED_assetlist_is_loaded(&library_ref)) { + BKE_reportf(reports, RPT_ERROR, "No asset found at path \"%s\"", full_path.c_str()); + } + } + return matching_asset; +} + +/** \note Does not check asset type or meta data. */ +static const asset_system::AssetRepresentation *get_asset(const bContext &C, + PointerRNA &ptr, + ReportList *reports) +{ + AssetWeakReference weak_ref{}; + weak_ref.asset_library_type = RNA_enum_get(&ptr, "asset_library_type"); + weak_ref.asset_library_identifier = RNA_string_get_alloc( + &ptr, "asset_library_identifier", nullptr, 0, nullptr); + weak_ref.relative_asset_identifier = RNA_string_get_alloc( + &ptr, "relative_asset_identifier", nullptr, 0, nullptr); + return find_asset_from_weak_ref(C, weak_ref, reports); +} + +static const bNodeTree *get_node_group(const bContext &C, PointerRNA &ptr, ReportList *reports) +{ + const asset_system::AssetRepresentation *asset = get_asset(C, ptr, reports); if (!asset) { return nullptr; } @@ -82,6 +166,9 @@ static const bNodeTree *get_node_group(const bContext &C) return nullptr; } if (node_group->type != NTREE_GEOMETRY) { + if (reports) { + BKE_report(reports, RPT_ERROR, "Asset is not a geometry node group"); + } return nullptr; } return node_group; @@ -217,7 +304,7 @@ static int run_node_group_exec(bContext *C, wmOperator *op) } const eObjectMode mode = eObjectMode(active_object->mode); - const bNodeTree *node_tree = get_node_group(*C); + const bNodeTree *node_tree = get_node_group(*C, *op->ptr, op->reports); if (!node_tree) { return OPERATOR_CANCELLED; } @@ -268,7 +355,7 @@ static int run_node_group_exec(bContext *C, wmOperator *op) static int run_node_group_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/) { - const bNodeTree *node_tree = get_node_group(*C); + const bNodeTree *node_tree = get_node_group(*C, *op->ptr, op->reports); if (!node_tree) { return OPERATOR_CANCELLED; } @@ -279,11 +366,9 @@ static int run_node_group_invoke(bContext *C, wmOperator *op, const wmEvent * /* return run_node_group_exec(C, op); } -static char *run_node_group_get_description(bContext *C, - wmOperatorType * /*ot*/, - PointerRNA * /*ptr*/) +static char *run_node_group_get_description(bContext *C, wmOperatorType * /*ot*/, PointerRNA *ptr) { - const asset_system::AssetRepresentation *asset = CTX_wm_asset(C); + const asset_system::AssetRepresentation *asset = get_asset(*C, *ptr, nullptr); if (!asset) { return nullptr; } @@ -294,34 +379,33 @@ static char *run_node_group_get_description(bContext *C, return BLI_strdup(description); } -static bool run_node_group_poll(bContext *C) -{ - const asset_system::AssetRepresentation *asset = CTX_wm_asset(C); - if (!asset) { - return false; - } - const Object *object = CTX_data_active_object(C); - if (object->type != OB_CURVES) { - return false; - } - if (object->mode != OB_MODE_SCULPT_CURVES) { - return false; - } - return true; -} - void GEOMETRY_OT_execute_node_group(wmOperatorType *ot) { ot->name = "Run Node Group"; ot->idname = __func__; ot->description = "Execute a node group on geometry"; - ot->poll = run_node_group_poll; + /* A proper poll is not possible, since it doesn't have access to the operator's properties. */ ot->invoke = run_node_group_invoke; ot->exec = run_node_group_exec; ot->get_description = run_node_group_get_description; ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + PropertyRNA *prop; + prop = RNA_def_enum(ot->srna, + "asset_library_type", + rna_enum_aset_library_type_items, + ASSET_LIBRARY_LOCAL, + "Asset Library Type", + ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + prop = RNA_def_string( + ot->srna, "asset_library_identifier", nullptr, 0, "Asset Library Identifier", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + prop = RNA_def_string( + ot->srna, "relative_asset_identifier", nullptr, 0, "Relative Asset Identifier", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } /** \} */ @@ -430,9 +514,20 @@ static void node_add_catalog_assets_draw(const bContext *C, Menu *menu) for (const asset_system::AssetRepresentation *asset : assets) { uiLayout *col = uiLayoutColumn(layout, false); - PointerRNA asset_ptr = asset::create_asset_rna_ptr(asset); - uiLayoutSetContextPointer(col, "asset", &asset_ptr); - uiItemO(col, IFACE_(asset->get_name().c_str()), ICON_NONE, "GEOMETRY_OT_execute_node_group"); + wmOperatorType *ot = WM_operatortype_find("GEOMETRY_OT_execute_node_group", true); + const std::unique_ptr weak_ref = asset->make_weak_reference(); + PointerRNA props_ptr; + uiItemFullO_ptr(col, + ot, + IFACE_(asset->get_name().c_str()), + ICON_NONE, + nullptr, + WM_OP_INVOKE_DEFAULT, + eUI_Item_Flag(0), + &props_ptr); + RNA_enum_set(&props_ptr, "asset_library_type", weak_ref->asset_library_type); + RNA_string_set(&props_ptr, "asset_library_identifier", weak_ref->asset_library_identifier); + RNA_string_set(&props_ptr, "relative_asset_identifier", weak_ref->relative_asset_identifier); } asset_system::AssetLibrary *all_library = ED_assetlist_library_get_once_available( diff --git a/source/blender/makesrna/RNA_enum_items.h b/source/blender/makesrna/RNA_enum_items.h index 7ceb29fe086..31d53b7b734 100644 --- a/source/blender/makesrna/RNA_enum_items.h +++ b/source/blender/makesrna/RNA_enum_items.h @@ -258,6 +258,8 @@ DEF_ENUM(rna_enum_nla_mode_extend_items) DEF_ENUM(rna_enum_nla_mode_blend_items) DEF_ENUM(rna_enum_keyblock_type_items) +DEF_ENUM(rna_enum_aset_library_type_items) + #endif #undef DEF_ENUM diff --git a/source/blender/makesrna/intern/rna_asset.cc b/source/blender/makesrna/intern/rna_asset.cc index 089f17d1608..9488ee33090 100644 --- a/source/blender/makesrna/intern/rna_asset.cc +++ b/source/blender/makesrna/intern/rna_asset.cc @@ -17,6 +17,14 @@ #include "rna_internal.h" +const EnumPropertyItem rna_enum_aset_library_type_items[] = { + {ASSET_LIBRARY_LOCAL, "LOCAL", 0, "Local", ""}, + {ASSET_LIBRARY_ALL, "ALL", 0, "All", ""}, + {ASSET_LIBRARY_ESSENTIALS, "ESSENTIALS", 0, "Essentials", ""}, + {ASSET_LIBRARY_CUSTOM, "CUSTOM", 0, "Custom", ""}, + {0, nullptr, 0, nullptr, nullptr}, +}; + #ifdef RNA_RUNTIME # include "AS_asset_library.h"