* Attempt to improve readability by using focused, coherent helper classes. * Replace ListBase with blender::Vector, which is more efficient and has a better API. * Split user reporting from error checking. * Use namespace (as we usually do for C++ code). * Remove unused headers
260 lines
6.4 KiB
C++
260 lines
6.4 KiB
C++
/*
|
|
* 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<PointerRNA>;
|
|
|
|
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<ID *>(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<ID *>(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;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
void ED_operatortypes_asset(void)
|
|
{
|
|
WM_operatortype_append(ASSET_OT_mark);
|
|
WM_operatortype_append(ASSET_OT_clear);
|
|
}
|