/* * 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 "BKE_context.h" #include "BKE_report.h" #include "BLI_vector.hh" #include "ED_asset.h" #include "RNA_access.h" #include "WM_api.h" #include "WM_types.h" /* -------------------------------------------------------------------- */ using PointerRNAVec = blender::Vector; static bool asset_operation_poll(bContext * /*C*/) { return U.experimental.use_asset_browser; } /** * Return the IDs to operate on as PointerRNA vector. Either a single one ("id" context member) or * multiple ones ("selected_ids" context member). */ static PointerRNAVec asset_operation_get_ids_from_context(const bContext *C) { PointerRNAVec ids; PointerRNA idptr = CTX_data_pointer_get_type(C, "id", &RNA_ID); if (idptr.data) { /* Single ID. */ ids.append(idptr); } else { ListBase list; CTX_data_selected_ids(C, &list); LISTBASE_FOREACH (CollectionPointerLink *, link, &list) { ids.append(link->ptr); } BLI_freelistN(&list); } return ids; } /* -------------------------------------------------------------------- */ class AssetMarkHelper { public: void operator()(const bContext &C, PointerRNAVec &ids); void reportResults(ReportList &reports) const; bool wasSuccessful() const; private: struct Stats { int tot_created = 0; int tot_already_asset = 0; ID *last_id = nullptr; }; Stats stats; }; void AssetMarkHelper::operator()(const bContext &C, PointerRNAVec &ids) { for (PointerRNA &ptr : ids) { BLI_assert(RNA_struct_is_ID(ptr.type)); ID *id = static_cast(ptr.data); if (id->asset_data) { stats.tot_already_asset++; continue; } if (ED_asset_mark_id(&C, id)) { stats.last_id = id; stats.tot_created++; } } } bool AssetMarkHelper::wasSuccessful() const { return stats.tot_created > 0; } void AssetMarkHelper::reportResults(ReportList &reports) const { /* User feedback on failure. */ if (!wasSuccessful()) { if ((stats.tot_already_asset > 0)) { BKE_report(&reports, RPT_ERROR, "Selected data-blocks are already assets (or do not support use as assets)"); } else { BKE_report(&reports, RPT_ERROR, "No data-blocks to create assets for found (or do not support use as assets)"); } } /* User feedback on success. */ else if (stats.tot_created == 1) { /* If only one data-block: Give more useful message by printing asset name. */ BKE_reportf(&reports, RPT_INFO, "Data-block '%s' is now an asset", stats.last_id->name + 2); } else { BKE_reportf(&reports, RPT_INFO, "%i data-blocks are now assets", stats.tot_created); } } static int asset_mark_exec(bContext *C, wmOperator *op) { PointerRNAVec ids = asset_operation_get_ids_from_context(C); AssetMarkHelper mark_helper; mark_helper(*C, ids); mark_helper.reportResults(*op->reports); if (!mark_helper.wasSuccessful()) { return OPERATOR_CANCELLED; } WM_main_add_notifier(NC_ID | NA_EDITED, nullptr); WM_main_add_notifier(NC_ASSET | NA_ADDED, nullptr); return OPERATOR_FINISHED; } static void ASSET_OT_mark(wmOperatorType *ot) { ot->name = "Mark Asset"; ot->description = "Enable easier reuse of selected data-blocks through the Asset Browser, with the help of " "customizable metadata (like previews, descriptions and tags)"; ot->idname = "ASSET_OT_mark"; ot->exec = asset_mark_exec; ot->poll = asset_operation_poll; ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /* -------------------------------------------------------------------- */ class AssetClearHelper { public: void operator()(PointerRNAVec &ids); void reportResults(ReportList &reports) const; bool wasSuccessful() const; private: struct Stats { int tot_cleared = 0; ID *last_id = nullptr; }; Stats stats; }; void AssetClearHelper::operator()(PointerRNAVec &ids) { for (PointerRNA &ptr : ids) { BLI_assert(RNA_struct_is_ID(ptr.type)); ID *id = static_cast(ptr.data); if (!id->asset_data) { continue; } if (ED_asset_clear_id(id)) { stats.tot_cleared++; stats.last_id = id; } } } void AssetClearHelper::reportResults(ReportList &reports) const { if (!wasSuccessful()) { BKE_report(&reports, RPT_ERROR, "No asset data-blocks selected/focused"); } else if (stats.tot_cleared == 1) { /* If only one data-block: Give more useful message by printing asset name. */ BKE_reportf( &reports, RPT_INFO, "Data-block '%s' is no asset anymore", stats.last_id->name + 2); } else { BKE_reportf(&reports, RPT_INFO, "%i data-blocks are no assets anymore", stats.tot_cleared); } } bool AssetClearHelper::wasSuccessful() const { return stats.tot_cleared > 0; } static int asset_clear_exec(bContext *C, wmOperator *op) { PointerRNAVec ids = asset_operation_get_ids_from_context(C); AssetClearHelper clear_helper; clear_helper(ids); clear_helper.reportResults(*op->reports); if (!clear_helper.wasSuccessful()) { return OPERATOR_CANCELLED; } WM_main_add_notifier(NC_ID | NA_EDITED, nullptr); WM_main_add_notifier(NC_ASSET | NA_REMOVED, nullptr); return OPERATOR_FINISHED; } static void ASSET_OT_clear(wmOperatorType *ot) { ot->name = "Clear Asset"; ot->description = "Delete all asset metadata and turn the selected asset data-blocks back into normal " "data-blocks"; ot->idname = "ASSET_OT_clear"; ot->exec = asset_clear_exec; ot->poll = asset_operation_poll; ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /* -------------------------------------------------------------------- */ static bool asset_list_refresh_poll(bContext *C) { const AssetLibraryReference *library = CTX_wm_asset_library(C); if (!library) { return false; } return ED_assetlist_storage_has_list_for_library(library); } static int asset_list_refresh_exec(bContext *C, wmOperator *UNUSED(unused)) { const AssetLibraryReference *library = CTX_wm_asset_library(C); ED_assetlist_clear(library, C); return OPERATOR_FINISHED; } static void ASSET_OT_list_refresh(struct wmOperatorType *ot) { /* identifiers */ ot->name = "Refresh Asset List"; ot->description = "Trigger a reread of the assets"; ot->idname = "ASSET_OT_list_refresh"; /* api callbacks */ ot->exec = asset_list_refresh_exec; ot->poll = asset_list_refresh_poll; } /* -------------------------------------------------------------------- */ void ED_operatortypes_asset(void) { WM_operatortype_append(ASSET_OT_mark); WM_operatortype_append(ASSET_OT_clear); WM_operatortype_append(ASSET_OT_list_refresh); }