diff --git a/release/scripts/startup/bl_ui/space_filebrowser.py b/release/scripts/startup/bl_ui/space_filebrowser.py index a811ba93c17..641812694c8 100644 --- a/release/scripts/startup/bl_ui/space_filebrowser.py +++ b/release/scripts/startup/bl_ui/space_filebrowser.py @@ -190,8 +190,7 @@ class FILEBROWSER_PT_filter(FileBrowserPanel, Panel): sub = row.column(align=True) - if context.preferences.experimental.use_extended_asset_browser: - sub.prop(params, "use_filter_asset_only") + sub.prop(params, "use_filter_asset_only") filter_id = params.filter_id for identifier in dir(filter_id): diff --git a/release/scripts/startup/bl_ui/space_outliner.py b/release/scripts/startup/bl_ui/space_outliner.py index 3d18160d90f..07fa2220915 100644 --- a/release/scripts/startup/bl_ui/space_outliner.py +++ b/release/scripts/startup/bl_ui/space_outliner.py @@ -313,10 +313,6 @@ class OUTLINER_MT_object(Menu): class OUTLINER_MT_asset(Menu): bl_label = "Assets" - @classmethod - def poll(cls, context): - return context.preferences.experimental.use_extended_asset_browser - def draw(self, context): layout = self.layout diff --git a/source/blender/editors/asset/CMakeLists.txt b/source/blender/editors/asset/CMakeLists.txt index 9017f136319..b9ef8e82bba 100644 --- a/source/blender/editors/asset/CMakeLists.txt +++ b/source/blender/editors/asset/CMakeLists.txt @@ -40,6 +40,7 @@ set(SRC intern/asset_mark_clear.cc intern/asset_ops.cc intern/asset_temp_id_consumer.cc + intern/asset_type.cc ED_asset_catalog.h ED_asset_catalog.hh @@ -50,6 +51,7 @@ set(SRC ED_asset_list.hh ED_asset_mark_clear.h ED_asset_temp_id_consumer.h + ED_asset_type.h intern/asset_library_reference.hh ) diff --git a/source/blender/editors/asset/ED_asset_type.h b/source/blender/editors/asset/ED_asset_type.h new file mode 100644 index 00000000000..ba0a3d2812f --- /dev/null +++ b/source/blender/editors/asset/ED_asset_type.h @@ -0,0 +1,55 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup edasset + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +struct ID; + +bool ED_asset_type_id_is_non_experimental(const struct ID *id); + +/** + * Check if the asset type for \a id (which doesn't need to be an asset right now) can be an asset, + * respecting the "Extended Asset Browser" experimental feature flag. + */ +bool ED_asset_type_is_supported(const ID *id); + +/** + * Get the filter flags (subset of #FILTER_ID_ALL) representing the asset ID types that may be + * turned into assets, respecting the "Extended Asset Browser" experimental feature flag. + * \note Does not check for #BKE_id_can_be_asset(), so may return filter flags for IDs that can + * never be assets. + */ +int64_t ED_asset_types_supported_as_filter_flags(void); + +/** + * Utility: A string enumerating the non-experimental asset types. This is useful info to + * the user, it should be displayed in tooltips or messages. Macro to support concatenating static + * strings with this (not all UI code supports dynamic strings nicely). + * Should start with a consonant, so usages can prefix it with "a" (not "an"). + */ +#define ED_ASSET_TYPE_IDS_NON_EXPERIMENTAL_UI_STRING "Pose Action" + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/editors/asset/intern/asset_mark_clear.cc b/source/blender/editors/asset/intern/asset_mark_clear.cc index e7516bc94c4..4be7376a1c3 100644 --- a/source/blender/editors/asset/intern/asset_mark_clear.cc +++ b/source/blender/editors/asset/intern/asset_mark_clear.cc @@ -39,6 +39,7 @@ #include "ED_asset_list.h" #include "ED_asset_mark_clear.h" +#include "ED_asset_type.h" bool ED_asset_mark_id(ID *id) { @@ -81,5 +82,9 @@ bool ED_asset_clear_id(ID *id) bool ED_asset_can_mark_single_from_context(const bContext *C) { /* Context needs a "id" pointer to be set for #ASSET_OT_mark()/#ASSET_OT_clear() to use. */ - return CTX_data_pointer_get_type_silent(C, "id", &RNA_ID).data != nullptr; + const ID *id = static_cast(CTX_data_pointer_get_type_silent(C, "id", &RNA_ID).data); + if (!id) { + return false; + } + return ED_asset_type_is_supported(id); } diff --git a/source/blender/editors/asset/intern/asset_ops.cc b/source/blender/editors/asset/intern/asset_ops.cc index da699768970..e2ae3b3893b 100644 --- a/source/blender/editors/asset/intern/asset_ops.cc +++ b/source/blender/editors/asset/intern/asset_ops.cc @@ -18,6 +18,7 @@ * \ingroup edasset */ +#include "BKE_asset.h" #include "BKE_asset_catalog.hh" #include "BKE_asset_library.hh" #include "BKE_context.h" @@ -45,30 +46,6 @@ using namespace blender; using PointerRNAVec = blender::Vector; -static PointerRNAVec asset_operation_get_ids_from_context(const bContext *C); -static PointerRNAVec asset_operation_get_nonexperimental_ids_from_context(const bContext *C); -static bool asset_type_is_nonexperimental(const ID_Type id_type); - -static bool asset_operation_experimental_feature_poll(bContext * /*C*/) -{ - /* At this moment only the pose library is non-experimental. Still, directly marking arbitrary - * Actions as asset is not part of the stable functionality; instead, the pose library "Create - * Pose Asset" operator should be used. Actions can still be marked as asset via - * `the_action.asset_mark()` (so a function call instead of this operator), which is what the - * pose library uses internally. */ - return U.experimental.use_extended_asset_browser; -} - -static bool asset_clear_poll(bContext *C) -{ - if (asset_operation_experimental_feature_poll(C)) { - return true; - } - - PointerRNAVec pointers = asset_operation_get_nonexperimental_ids_from_context(C); - return !pointers.is_empty(); -} - /** * Return the IDs to operate on as PointerRNA vector. Either a single one ("id" context member) or * multiple ones ("selected_ids" context member). @@ -94,26 +71,51 @@ static PointerRNAVec asset_operation_get_ids_from_context(const bContext *C) return ids; } -static PointerRNAVec asset_operation_get_nonexperimental_ids_from_context(const bContext *C) +/** + * Information about what's contained in a #PointerRNAVec, returned by + * #asset_operation_get_id_vec_stats_from_context(). + */ +struct IDVecStats { + bool has_asset = false; + bool has_supported_type = false; + bool is_single = false; +}; + +/** + * Helper to report stats about the IDs in context. Operator polls use this, also to report a + * helpful disabled hint to the user. + */ +static IDVecStats asset_operation_get_id_vec_stats_from_context(const bContext *C) { - PointerRNAVec nonexperimental; PointerRNAVec pointers = asset_operation_get_ids_from_context(C); + IDVecStats stats; + + stats.is_single = pointers.size() == 1; + for (PointerRNA &ptr : pointers) { BLI_assert(RNA_struct_is_ID(ptr.type)); ID *id = static_cast(ptr.data); - if (asset_type_is_nonexperimental(GS(id->name))) { - nonexperimental.append(ptr); + if (ED_asset_type_is_supported(id)) { + stats.has_supported_type = true; + } + if (ID_IS_ASSET(id)) { + stats.has_asset = true; } } - return nonexperimental; + + return stats; } -static bool asset_type_is_nonexperimental(const ID_Type id_type) +static const char *asset_operation_unsupported_type_msg(const bool is_single) { - /* At this moment only the pose library is non-experimental. For simplicity, allow asset - * operations on all Action datablocks (even though pose assets are limited to single frames). */ - return ELEM(id_type, ID_AC); + const char *msg_single = + "Data-block does not support asset operations - must be " + "a " ED_ASSET_TYPE_IDS_NON_EXPERIMENTAL_UI_STRING; + const char *msg_multiple = + "No data-block selected that supports asset operations - select at least " + "one " ED_ASSET_TYPE_IDS_NON_EXPERIMENTAL_UI_STRING; + return is_single ? msg_single : msg_multiple; } /* -------------------------------------------------------------------- */ @@ -203,6 +205,18 @@ static int asset_mark_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } +static bool asset_mark_poll(bContext *C) +{ + IDVecStats ctx_stats = asset_operation_get_id_vec_stats_from_context(C); + + if (!ctx_stats.has_supported_type) { + CTX_wm_operator_poll_msg_set(C, asset_operation_unsupported_type_msg(ctx_stats.is_single)); + return false; + } + + return true; +} + static void ASSET_OT_mark(wmOperatorType *ot) { ot->name = "Mark as Asset"; @@ -212,7 +226,7 @@ static void ASSET_OT_mark(wmOperatorType *ot) ot->idname = "ASSET_OT_mark"; ot->exec = asset_mark_exec; - ot->poll = asset_operation_experimental_feature_poll; + ot->poll = asset_mark_poll; ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } @@ -315,6 +329,24 @@ static int asset_clear_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } +static bool asset_clear_poll(bContext *C) +{ + IDVecStats ctx_stats = asset_operation_get_id_vec_stats_from_context(C); + + if (!ctx_stats.has_asset) { + const char *msg_single = "Data-block is not marked as asset"; + const char *msg_multiple = "No data-block selected that is marked as asset"; + CTX_wm_operator_poll_msg_set(C, ctx_stats.is_single ? msg_single : msg_multiple); + return false; + } + if (!ctx_stats.has_supported_type) { + CTX_wm_operator_poll_msg_set(C, asset_operation_unsupported_type_msg(ctx_stats.is_single)); + return false; + } + + return true; +} + static char *asset_clear_get_description(struct bContext *UNUSED(C), struct wmOperatorType *UNUSED(op), struct PointerRNA *values) diff --git a/source/blender/editors/asset/intern/asset_type.cc b/source/blender/editors/asset/intern/asset_type.cc new file mode 100644 index 00000000000..1b8e56974bf --- /dev/null +++ b/source/blender/editors/asset/intern/asset_type.cc @@ -0,0 +1,62 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup edasset + */ + +#include "BLI_utildefines.h" + +#include "DNA_userdef_types.h" + +#include "BKE_lib_id.h" + +#include "ED_asset_type.h" + +bool ED_asset_type_id_is_non_experimental(const ID *id) +{ + /* Remember to update #ED_ASSET_TYPE_IDS_NON_EXPERIMENTAL_UI_STRING and + * #asset_type_ids_non_experimental_as_filter_flags() with this! */ + return ELEM(GS(id->name), ID_AC); +} +static int64_t asset_type_ids_non_experimental_as_filter_flags() +{ + return FILTER_ID_AC; +} + +bool ED_asset_type_is_supported(const ID *id) +{ + if (!BKE_id_can_be_asset(id)) { + return false; + } + + if (U.experimental.use_extended_asset_browser) { + /* The "Extended Asset Browser" experimental feature flag enables all asset types that can + * technically be assets. */ + return true; + } + + return ED_asset_type_id_is_non_experimental(id); +} + +int64_t ED_asset_types_supported_as_filter_flags() +{ + if (U.experimental.use_extended_asset_browser) { + return FILTER_ID_ALL; + } + + return asset_type_ids_non_experimental_as_filter_flags(); +} diff --git a/source/blender/editors/include/ED_asset.h b/source/blender/editors/include/ED_asset.h index 6b8d33fa713..3b1d87e8ff7 100644 --- a/source/blender/editors/include/ED_asset.h +++ b/source/blender/editors/include/ED_asset.h @@ -43,6 +43,7 @@ void ED_operatortypes_asset(void); #include "../asset/ED_asset_list.h" #include "../asset/ED_asset_mark_clear.h" #include "../asset/ED_asset_temp_id_consumer.h" +#include "../asset/ED_asset_type.h" /* C++ only headers. */ #ifdef __cplusplus diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c index 9e436601132..1e4f1a7f5dc 100644 --- a/source/blender/editors/interface/interface_context_menu.c +++ b/source/blender/editors/interface/interface_context_menu.c @@ -937,7 +937,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but, const wmEvent *ev } /* If the button represents an id, it can set the "id" context pointer. */ - if (U.experimental.use_extended_asset_browser && ED_asset_can_mark_single_from_context(C)) { + if (ED_asset_can_mark_single_from_context(C)) { ID *id = CTX_data_pointer_get_type(C, "id", &RNA_ID).data; /* Gray out items depending on if data-block is an asset. Preferably this could be done via diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index b93f9b34f3b..b5c395c8bc2 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -43,6 +43,7 @@ #include "WM_message.h" #include "WM_types.h" +#include "ED_asset.h" #include "ED_fileselect.h" #include "ED_screen.h" #include "ED_space_api.h" @@ -327,8 +328,8 @@ static void file_refresh(const bContext *C, ScrArea *area) } if (ED_fileselect_is_asset_browser(sfile)) { - /* Only poses supported as non-experimental right now. */ - params->filter_id = U.experimental.use_extended_asset_browser ? FILTER_ID_ALL : FILTER_ID_AC; + /* Ask the asset code for appropriate ID filter flags for the supported assets. */ + params->filter_id = ED_asset_types_supported_as_filter_flags(); } filelist_settype(sfile->files, params->type);