Refactor: extract utility functions from brush asset code

No functional changes intended.

Some functionality from the brush asset system will be reused by the pose library.
To avoid duplicating code, the relevant functions are extracted to a common place.

All functions are moved as is, except for `visit_library_catalogs_catalog_for_search`.
For that I changed the `bUserAssetLibrary` argument to a `AssetLibraryReference`.
That is because in the follow up PR I am using this function with non user libraries as well.

This is a refactor PR extracted from #132747.
To get a full picture of the use case see that PR.

Part of #131840

Pull Request: https://projects.blender.org/blender/blender/pulls/132857
This commit is contained in:
Christoph Lendenfeld 2025-01-17 17:11:03 +01:00 committed by Christoph Lendenfeld
parent 8117e1981a
commit 3f76352149
6 changed files with 190 additions and 114 deletions

View file

@ -21,6 +21,7 @@ set(SRC
intern/asset_handle.cc
intern/asset_import.cc
intern/asset_indexer.cc
intern/asset_library_utils.cc
intern/asset_library_reference_enum.cc
intern/asset_list.cc
intern/asset_mark_clear.cc

View file

@ -10,7 +10,16 @@
#include "DNA_asset_types.h"
struct bUserAssetLibrary;
struct bContext;
struct AssetLibraryReference;
struct EnumPropertyItem;
struct StringPropertySearchVisitParams;
namespace blender::asset_system {
class AssetCatalog;
class AssetCatalogPath;
} // namespace blender::asset_system
namespace blender::ed::asset {
@ -38,4 +47,23 @@ AssetLibraryReference library_reference_from_enum_value(int value);
*/
const EnumPropertyItem *library_reference_to_rna_enum_itemf(bool include_generated);
/**
* Find the catalog with the given path in the library. Creates it in case it doesn't exist.
*/
blender::asset_system::AssetCatalog &library_ensure_catalogs_in_path(
blender::asset_system::AssetLibrary &library,
const blender::asset_system::AssetCatalogPath &path);
/**
* May return a nullptr if the given AssetLibraryReference is not a user library.
*/
const bUserAssetLibrary *library_ref_to_user_library(const AssetLibraryReference &library_ref);
AssetLibraryReference user_library_to_library_ref(const bUserAssetLibrary &user_library);
/**
* Call after changes to an asset library have been made to reflect the changes in the UI.
*/
void refresh_asset_library(const bContext *C, const AssetLibraryReference &library_ref);
void refresh_asset_library(const bContext *C, const bUserAssetLibrary &user_library);
} // namespace blender::ed::asset

View file

@ -0,0 +1,93 @@
/* SPDX-FileCopyrightText: 2024 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup edasset
*/
#include "BKE_context.hh"
#include "BKE_preferences.h"
#include "ED_asset_library.hh"
#include "ED_asset_list.hh"
#include "ED_asset_shelf.hh"
#include "BLI_listbase.h"
#include "BLI_string_ref.hh"
#include "DNA_userdef_types.h"
#include "RNA_access.hh"
#include "UI_resources.hh"
#include "WM_api.hh"
#include "AS_asset_catalog.hh"
#include "AS_asset_catalog_tree.hh"
#include "AS_asset_library.hh"
namespace blender::ed::asset {
static asset_system::AssetCatalog &library_ensure_catalog(
asset_system::AssetLibrary &library, const asset_system::AssetCatalogPath &path)
{
if (asset_system::AssetCatalog *catalog = library.catalog_service().find_catalog_by_path(path)) {
return *catalog;
}
return *library.catalog_service().create_catalog(path);
}
/* Suppress warning for GCC-14.2. This isn't a dangling reference
* because the #asset_system::AssetLibrary owns the returned value. */
#if defined(__GNUC__) && !defined(__clang__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdangling-reference"
#endif
blender::asset_system::AssetCatalog &library_ensure_catalogs_in_path(
asset_system::AssetLibrary &library, const blender::asset_system::AssetCatalogPath &path)
{
/* Adding multiple catalogs in a path at a time with #AssetCatalogService::create_catalog()
* doesn't work; add each potentially new catalog in the hierarchy manually here. */
asset_system::AssetCatalogPath parent = "";
path.iterate_components([&](StringRef component_name, bool /*is_last_component*/) {
library_ensure_catalog(library, parent / component_name);
parent = parent / component_name;
});
return *library.catalog_service().find_catalog_by_path(path);
}
#if defined(__GNUC__) && !defined(__clang__)
# pragma GCC diagnostic pop
#endif
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;
}
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));
}
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? */
AssetLibraryReference all_lib_ref = asset_system::all_library_reference();
asset::list::clear(&all_lib_ref, C);
}
void refresh_asset_library(const bContext *C, const bUserAssetLibrary &user_library)
{
refresh_asset_library(C, user_library_to_library_ref(user_library));
}
} // namespace blender::ed::asset

View file

@ -8,9 +8,14 @@
#include <string>
#include "AS_asset_library.hh"
#include "AS_asset_representation.hh"
#include "BKE_preferences.h"
#include "DNA_userdef_types.h"
#include "ED_asset.hh"
#include "RNA_access.hh"
#include "UI_resources.hh"
namespace blender::ed::asset {
@ -30,4 +35,35 @@ std::string asset_tooltip(const asset_system::AssetRepresentation &asset, const
return complete_string;
}
const bUserAssetLibrary *get_asset_library_from_opptr(PointerRNA &ptr)
{
const int enum_value = RNA_enum_get(&ptr, "asset_library_reference");
const AssetLibraryReference lib_ref = asset::library_reference_from_enum_value(enum_value);
return BKE_preferences_asset_library_find_index(&U, lib_ref.custom_library_index);
}
void visit_library_catalogs_catalog_for_search(
const Main &bmain,
const AssetLibraryReference lib,
const StringRef edit_text,
const FunctionRef<void(StringPropertySearchVisitParams)> visit_fn)
{
const asset_system::AssetLibrary *library = AS_asset_library_load(&bmain, lib);
if (!library) {
return;
}
if (!edit_text.is_empty()) {
const asset_system::AssetCatalogPath edit_path = edit_text;
if (!library->catalog_service().find_catalog_by_path(edit_path)) {
visit_fn(StringPropertySearchVisitParams{edit_path.str(), std::nullopt, ICON_ADD});
}
}
const asset_system::AssetCatalogTree &full_tree = library->catalog_service().catalog_tree();
full_tree.foreach_item([&](const asset_system::AssetCatalogTreeItem &item) {
visit_fn(StringPropertySearchVisitParams{item.catalog_path().str(), std::nullopt});
});
}
} // namespace blender::ed::asset

View file

@ -27,6 +27,8 @@
#include "../asset/ED_asset_import.hh" // IWYU pragma: export
#include "../asset/ED_asset_list.hh" // IWYU pragma: export
struct PointerRNA;
namespace blender::ed::asset {
std::string asset_tooltip(const asset_system::AssetRepresentation &asset,
@ -34,4 +36,18 @@ std::string asset_tooltip(const asset_system::AssetRepresentation &asset,
void operatortypes_asset();
/**
* The PointerRNA is expected to have an enum called "asset_library_reference".
*/
const bUserAssetLibrary *get_asset_library_from_opptr(PointerRNA &ptr);
/**
* For each catalog of the given bUserAssetLibrary call `visit_fn`.
*/
void visit_library_catalogs_catalog_for_search(
const Main &bmain,
const AssetLibraryReference lib,
const StringRef edit_text,
const FunctionRef<void(StringPropertySearchVisitParams)> visit_fn);
} // namespace blender::ed::asset

View file

@ -29,6 +29,7 @@
#include "RNA_access.hh"
#include "RNA_define.hh"
#include "ED_asset.hh"
#include "ED_asset_handle.hh"
#include "ED_asset_library.hh"
#include "ED_asset_list.hh"
@ -37,7 +38,6 @@
#include "ED_asset_shelf.hh"
#include "UI_interface_icons.hh"
#include "UI_resources.hh"
#include "BLT_translation.hh"
@ -106,37 +106,6 @@ static std::optional<AssetLibraryReference> library_to_library_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? */
AssetLibraryReference all_lib_ref = asset_system::all_library_reference();
asset::list::clear(&all_lib_ref, C);
}
static void refresh_asset_library(const bContext *C, const bUserAssetLibrary &user_library)
{
refresh_asset_library(C, user_library_to_library_ref(user_library));
}
static bool brush_asset_save_as_poll(bContext *C)
{
Paint *paint = BKE_paint_get_active_from_context(C);
@ -158,45 +127,6 @@ static bool brush_asset_save_as_poll(bContext *C)
return true;
}
static const bUserAssetLibrary *get_asset_library_from_prop(PointerRNA &ptr)
{
const int enum_value = RNA_enum_get(&ptr, "asset_library_reference");
const AssetLibraryReference lib_ref = asset::library_reference_from_enum_value(enum_value);
return BKE_preferences_asset_library_find_index(&U, lib_ref.custom_library_index);
}
static asset_system::AssetCatalog &asset_library_ensure_catalog(
asset_system::AssetLibrary &library, const asset_system::AssetCatalogPath &path)
{
if (asset_system::AssetCatalog *catalog = library.catalog_service().find_catalog_by_path(path)) {
return *catalog;
}
return *library.catalog_service().create_catalog(path);
}
/* Suppress warning for GCC-14.2. This isn't a dangling reference
* because the #asset_system::AssetLibrary owns the returned value. */
#if defined(__GNUC__) && !defined(__clang__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdangling-reference"
#endif
static asset_system::AssetCatalog &asset_library_ensure_catalogs_in_path(
asset_system::AssetLibrary &library, const asset_system::AssetCatalogPath &path)
{
/* Adding multiple catalogs in a path at a time with #AssetCatalogService::create_catalog()
* doesn't work; add each potentially new catalog in the hierarchy manually here. */
asset_system::AssetCatalogPath parent = "";
path.iterate_components([&](StringRef component_name, bool /*is_last_component*/) {
asset_library_ensure_catalog(library, parent / component_name);
parent = parent / component_name;
});
return *library.catalog_service().find_catalog_by_path(path);
}
#if defined(__GNUC__) && !defined(__clang__)
# pragma GCC diagnostic pop
#endif
static int brush_asset_save_as_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@ -213,13 +143,13 @@ static int brush_asset_save_as_exec(bContext *C, wmOperator *op)
STRNCPY(name, brush->id.name + 2);
}
const bUserAssetLibrary *user_library = get_asset_library_from_prop(*op->ptr);
const bUserAssetLibrary *user_library = asset::get_asset_library_from_opptr(*op->ptr);
if (!user_library) {
return OPERATOR_CANCELLED;
}
asset_system::AssetLibrary *library = AS_asset_library_load(
bmain, user_library_to_library_ref(*user_library));
bmain, asset::user_library_to_library_ref(*user_library));
if (!library) {
BKE_report(op->reports, RPT_ERROR, "Failed to load asset library");
return OPERATOR_CANCELLED;
@ -238,7 +168,7 @@ static int brush_asset_save_as_exec(bContext *C, wmOperator *op)
AssetMetaData &meta_data = *brush->id.asset_data;
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);
BKE_asset_metadata_catalog_id_set(&meta_data, catalog.catalog_id, catalog.simple_name.c_str());
}
@ -262,7 +192,7 @@ static int brush_asset_save_as_exec(bContext *C, wmOperator *op)
BKE_report(op->reports, RPT_WARNING, "Unable to activate just-saved brush asset");
}
refresh_asset_library(C, *user_library);
asset::refresh_asset_library(C, *user_library);
WM_main_add_notifier(NC_ASSET | ND_ASSET_LIST | NA_ADDED, nullptr);
WM_main_add_notifier(NC_BRUSH | NA_EDITED, brush);
@ -304,7 +234,7 @@ static int brush_asset_save_as_invoke(bContext *C, wmOperator *op, const wmEvent
asset::library_reference_to_enum_value(&*library_ref));
}
else {
const AssetLibraryReference first_library = user_library_to_library_ref(
const AssetLibraryReference first_library = asset::user_library_to_library_ref(
*static_cast<const bUserAssetLibrary *>(U.asset_libraries.first));
RNA_enum_set(op->ptr,
"asset_library_reference",
@ -338,31 +268,6 @@ static const EnumPropertyItem *rna_asset_library_reference_itemf(bContext * /*C*
return items;
}
static void visit_library_catalogs_catalog_for_search(
const Main &bmain,
const bUserAssetLibrary &user_library,
const StringRef edit_text,
const FunctionRef<void(StringPropertySearchVisitParams)> visit_fn)
{
const asset_system::AssetLibrary *library = AS_asset_library_load(
&bmain, user_library_to_library_ref(user_library));
if (!library) {
return;
}
if (!edit_text.is_empty()) {
const asset_system::AssetCatalogPath edit_path = edit_text;
if (!library->catalog_service().find_catalog_by_path(edit_path)) {
visit_fn(StringPropertySearchVisitParams{edit_path.str(), std::nullopt, ICON_ADD});
}
}
const asset_system::AssetCatalogTree &full_tree = library->catalog_service().catalog_tree();
full_tree.foreach_item([&](const asset_system::AssetCatalogTreeItem &item) {
visit_fn(StringPropertySearchVisitParams{item.catalog_path().str(), std::nullopt});
});
}
static void visit_library_prop_catalogs_catalog_for_search_fn(
const bContext *C,
PointerRNA *ptr,
@ -371,9 +276,9 @@ static void visit_library_prop_catalogs_catalog_for_search_fn(
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);
if (const bUserAssetLibrary *user_library = asset::get_asset_library_from_opptr(*ptr)) {
asset::visit_library_catalogs_catalog_for_search(
*CTX_data_main(C), asset::user_library_to_library_ref(*user_library), edit_text, visit_fn);
}
}
@ -428,7 +333,7 @@ static int brush_asset_edit_metadata_exec(bContext *C, wmOperator *op)
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(
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());
}
@ -448,7 +353,7 @@ static int brush_asset_edit_metadata_exec(bContext *C, wmOperator *op)
library->catalog_service().write_to_disk(file_path);
refresh_asset_library(C, library_ref);
asset::refresh_asset_library(C, library_ref);
WM_main_add_notifier(NC_ASSET | ND_ASSET_LIST | NA_EDITED, nullptr);
return OPERATOR_FINISHED;
@ -499,11 +404,8 @@ static void visit_active_library_catalogs_catalog_for_search_fn(
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);
asset::visit_library_catalogs_catalog_for_search(
*CTX_data_main(C), *library_to_library_ref(library), edit_text, visit_fn);
}
static bool brush_asset_edit_metadata_poll(bContext *C)
@ -590,7 +492,7 @@ static int brush_asset_load_preview_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
refresh_asset_library(C, library_ref);
asset::refresh_asset_library(C, library_ref);
WM_main_add_notifier(NC_ASSET | ND_ASSET_LIST | NA_EDITED, nullptr);
return OPERATOR_FINISHED;
@ -658,7 +560,7 @@ static int brush_asset_delete_exec(bContext *C, wmOperator *op)
BKE_paint_brush_set_default(bmain, paint);
if (library) {
refresh_asset_library(C, *library);
asset::refresh_asset_library(C, *library);
}
WM_main_add_notifier(NC_ASSET | ND_ASSET_LIST | NA_REMOVED, nullptr);
@ -737,7 +639,7 @@ static int brush_asset_save_exec(bContext *C, wmOperator *op)
bke::asset_edit_id_save(*bmain, brush->id, *op->reports);
brush->has_unsaved_changes = false;
refresh_asset_library(C, *user_library);
asset::refresh_asset_library(C, *user_library);
WM_main_add_notifier(NC_ASSET | ND_ASSET_LIST | NA_EDITED, nullptr);
WM_main_add_notifier(NC_BRUSH | NA_EDITED, brush);