tornavis/source/blender/editors/space_file/asset_catalog_tree_view.cc

775 lines
27 KiB
C++

/* SPDX-FileCopyrightText: 2021 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup spfile
*/
#include "DNA_space_types.h"
#include "AS_asset_catalog.hh"
#include "AS_asset_catalog_tree.hh"
#include "AS_asset_library.hh"
#include "BKE_asset.hh"
#include "BLI_string_ref.hh"
#include "BLT_translation.hh"
#include "ED_asset.hh"
#include "ED_fileselect.hh"
#include "ED_undo.hh"
#include "RNA_access.hh"
#include "UI_interface.hh"
#include "UI_resources.hh"
#include "UI_tree_view.hh"
#include "WM_api.hh"
#include "WM_types.hh"
#include "file_intern.hh"
#include "filelist.hh"
#include <fmt/format.h>
using namespace blender::asset_system;
namespace blender::ed::asset_browser {
class AssetCatalogTreeViewAllItem;
class AssetCatalogTreeView : public ui::AbstractTreeView {
asset_system::AssetLibrary *asset_library_;
/** The asset catalog tree this tree-view represents. */
const asset_system::AssetCatalogTree *catalog_tree_;
FileAssetSelectParams *params_;
SpaceFile &space_file_;
friend class AssetCatalogTreeViewItem;
friend class AssetCatalogDropTarget;
friend class AssetCatalogTreeViewAllItem;
public:
AssetCatalogTreeView(asset_system::AssetLibrary *library,
FileAssetSelectParams *params,
SpaceFile &space_file);
void build_tree() override;
void activate_catalog_by_id(CatalogID catalog_id);
private:
ui::BasicTreeViewItem &build_catalog_items_recursive(ui::TreeViewOrItem &view_parent_item,
const AssetCatalogTreeItem &catalog);
AssetCatalogTreeViewAllItem &add_all_item();
void add_unassigned_item();
bool is_active_catalog(CatalogID catalog_id) const;
};
/* ---------------------------------------------------------------------- */
class AssetCatalogTreeViewItem : public ui::BasicTreeViewItem {
/** The catalog tree item this tree view item represents. */
const AssetCatalogTreeItem &catalog_item_;
public:
AssetCatalogTreeViewItem(const AssetCatalogTreeItem &catalog_item);
void on_activate(bContext &C) override;
void build_row(uiLayout &row) override;
void build_context_menu(bContext &C, uiLayout &column) const override;
bool supports_renaming() const override;
bool rename(const bContext &C, StringRefNull new_name) override;
/** Add drag support for catalog items. */
std::unique_ptr<ui::AbstractViewItemDragController> create_drag_controller() const override;
/** Add dropping support for catalog items. */
std::unique_ptr<ui::TreeViewItemDropTarget> create_drop_target() override;
};
class AssetCatalogDragController : public ui::AbstractViewItemDragController {
const AssetCatalogTreeItem &catalog_item_;
public:
explicit AssetCatalogDragController(AssetCatalogTreeView &tree_view,
const AssetCatalogTreeItem &catalog_item);
eWM_DragDataType get_drag_type() const override;
void *create_drag_data() const override;
void on_drag_start() override;
};
class AssetCatalogDropTarget : public ui::TreeViewItemDropTarget {
const AssetCatalogTreeItem &catalog_item_;
public:
AssetCatalogDropTarget(AssetCatalogTreeViewItem &item, const AssetCatalogTreeItem &catalog_item);
bool can_drop(const wmDrag &drag, const char **r_disabled_hint) const override;
std::string drop_tooltip(const ui::DragInfo &drag_info) const override;
bool on_drop(bContext *C, const ui::DragInfo &drag_info) const override;
asset_system::AssetLibrary &get_asset_library() const;
static AssetCatalog *get_drag_catalog(const wmDrag &drag,
const asset_system::AssetLibrary &asset_library);
static bool has_droppable_asset(const wmDrag &drag, const char **r_disabled_hint);
static bool can_modify_catalogs(const asset_system::AssetLibrary &asset_library,
const char **r_disabled_hint);
static bool drop_assets_into_catalog(bContext *C,
const AssetCatalogTreeView &tree_view,
const wmDrag &drag,
CatalogID catalog_id,
StringRefNull simple_name = "");
/**
* \param drop_catalog_id: Can be unset to drop into the root level of the tree.
*/
static bool drop_asset_catalog_into_catalog(
const wmDrag &drag,
AssetCatalogTreeView &tree_view,
const std::optional<CatalogID> drop_catalog_id = std::nullopt);
private:
std::string drop_tooltip_asset_list(const wmDrag &drag) const;
std::string drop_tooltip_asset_catalog(const wmDrag &drag) const;
};
/**
* Only reason this isn't just `BasicTreeViewItem` is to add a '+' icon for adding a root level
* catalog.
*/
class AssetCatalogTreeViewAllItem : public ui::BasicTreeViewItem {
using BasicTreeViewItem::BasicTreeViewItem;
void build_row(uiLayout &row) override;
struct DropTarget : public ui::TreeViewItemDropTarget {
DropTarget(AssetCatalogTreeViewAllItem &item);
bool can_drop(const wmDrag &drag, const char **r_disabled_hint) const override;
std::string drop_tooltip(const ui::DragInfo &drag_info) const override;
bool on_drop(bContext *C, const ui::DragInfo &drag_info) const override;
};
std::unique_ptr<ui::TreeViewItemDropTarget> create_drop_target() override;
};
class AssetCatalogTreeViewUnassignedItem : public ui::BasicTreeViewItem {
using BasicTreeViewItem::BasicTreeViewItem;
struct DropTarget : public ui::TreeViewItemDropTarget {
DropTarget(AssetCatalogTreeViewUnassignedItem &item);
bool can_drop(const wmDrag &drag, const char **r_disabled_hint) const override;
std::string drop_tooltip(const ui::DragInfo &drag_info) const override;
bool on_drop(bContext *C, const ui::DragInfo &drag_info) const override;
};
std::unique_ptr<ui::TreeViewItemDropTarget> create_drop_target() override;
};
/* ---------------------------------------------------------------------- */
AssetCatalogTreeView::AssetCatalogTreeView(asset_system::AssetLibrary *library,
FileAssetSelectParams *params,
SpaceFile &space_file)
: asset_library_(library), params_(params), space_file_(space_file)
{
if (library) {
catalog_tree_ = &library->catalog_service().catalog_tree();
}
else {
catalog_tree_ = nullptr;
}
}
void AssetCatalogTreeView::build_tree()
{
AssetCatalogTreeViewAllItem &all_item = add_all_item();
all_item.uncollapse_by_default();
if (catalog_tree_) {
/* Pass the "All" item on as parent of the actual catalog items. */
catalog_tree_->foreach_root_item([this, &all_item](const AssetCatalogTreeItem &item) {
build_catalog_items_recursive(all_item, item);
});
}
add_unassigned_item();
}
ui::BasicTreeViewItem &AssetCatalogTreeView::build_catalog_items_recursive(
ui::TreeViewOrItem &view_parent_item, const AssetCatalogTreeItem &catalog)
{
ui::BasicTreeViewItem &view_item = view_parent_item.add_tree_item<AssetCatalogTreeViewItem>(
catalog);
view_item.set_is_active_fn(
[this, &catalog]() { return is_active_catalog(catalog.get_catalog_id()); });
catalog.foreach_child([&view_item, this](const AssetCatalogTreeItem &child) {
build_catalog_items_recursive(view_item, child);
});
return view_item;
}
AssetCatalogTreeViewAllItem &AssetCatalogTreeView::add_all_item()
{
FileAssetSelectParams *params = params_;
AssetCatalogTreeViewAllItem &item = add_tree_item<AssetCatalogTreeViewAllItem>(IFACE_("All"));
item.set_on_activate_fn([params](bContext & /*C*/, ui::BasicTreeViewItem & /*item*/) {
params->asset_catalog_visibility = FILE_SHOW_ASSETS_ALL_CATALOGS;
WM_main_add_notifier(NC_SPACE | ND_SPACE_ASSET_PARAMS, nullptr);
});
item.set_is_active_fn(
[params]() { return params->asset_catalog_visibility == FILE_SHOW_ASSETS_ALL_CATALOGS; });
return item;
}
void AssetCatalogTreeView::add_unassigned_item()
{
FileAssetSelectParams *params = params_;
AssetCatalogTreeViewUnassignedItem &item = add_tree_item<AssetCatalogTreeViewUnassignedItem>(
IFACE_("Unassigned"), ICON_FILE_HIDDEN);
item.set_on_activate_fn([params](bContext & /*C*/, ui::BasicTreeViewItem & /*item*/) {
params->asset_catalog_visibility = FILE_SHOW_ASSETS_WITHOUT_CATALOG;
WM_main_add_notifier(NC_SPACE | ND_SPACE_ASSET_PARAMS, nullptr);
});
item.set_is_active_fn(
[params]() { return params->asset_catalog_visibility == FILE_SHOW_ASSETS_WITHOUT_CATALOG; });
}
void AssetCatalogTreeView::activate_catalog_by_id(CatalogID catalog_id)
{
params_->asset_catalog_visibility = FILE_SHOW_ASSETS_FROM_CATALOG;
params_->catalog_id = catalog_id;
WM_main_add_notifier(NC_SPACE | ND_SPACE_ASSET_PARAMS, nullptr);
}
bool AssetCatalogTreeView::is_active_catalog(CatalogID catalog_id) const
{
return (params_->asset_catalog_visibility == FILE_SHOW_ASSETS_FROM_CATALOG) &&
(params_->catalog_id == catalog_id);
}
/* ---------------------------------------------------------------------- */
AssetCatalogTreeViewItem::AssetCatalogTreeViewItem(const AssetCatalogTreeItem &catalog_item)
: BasicTreeViewItem(catalog_item.get_name()), catalog_item_(catalog_item)
{
}
void AssetCatalogTreeViewItem::on_activate(bContext & /*C*/)
{
AssetCatalogTreeView &tree_view = static_cast<AssetCatalogTreeView &>(get_tree_view());
tree_view.activate_catalog_by_id(catalog_item_.get_catalog_id());
}
void AssetCatalogTreeViewItem::build_row(uiLayout &row)
{
const std::string label_override = catalog_item_.has_unsaved_changes() ? (label_ + "*") : label_;
this->add_label(row, label_override);
if (!is_hovered()) {
return;
}
uiButViewItem *view_item_but = view_item_button();
PointerRNA *props;
props = UI_but_extra_operator_icon_add(
(uiBut *)view_item_but, "ASSET_OT_catalog_new", WM_OP_INVOKE_DEFAULT, ICON_ADD);
RNA_string_set(props, "parent_path", catalog_item_.catalog_path().c_str());
}
void AssetCatalogTreeViewItem::build_context_menu(bContext &C, uiLayout &column) const
{
PointerRNA props;
uiItemFullO(&column,
"ASSET_OT_catalog_new",
IFACE_("New Catalog"),
ICON_NONE,
nullptr,
WM_OP_INVOKE_DEFAULT,
UI_ITEM_NONE,
&props);
RNA_string_set(&props, "parent_path", catalog_item_.catalog_path().c_str());
uiItemFullO(&column,
"ASSET_OT_catalog_delete",
IFACE_("Delete Catalog"),
ICON_NONE,
nullptr,
WM_OP_INVOKE_DEFAULT,
UI_ITEM_NONE,
&props);
RNA_string_set(&props, "catalog_id", catalog_item_.get_catalog_id().str().c_str());
uiItemO(&column, IFACE_("Rename"), ICON_NONE, "UI_OT_view_item_rename");
/* Doesn't actually exist right now, but could be defined in Python. Reason that this isn't done
* in Python yet is that catalogs are not exposed in BPY, and we'd somehow pass the clicked on
* catalog to the menu draw callback (via context probably). */
MenuType *mt = WM_menutype_find("ASSETBROWSER_MT_catalog_context_menu", true);
if (!mt) {
return;
}
UI_menutype_draw(&C, mt, &column);
}
bool AssetCatalogTreeViewItem::supports_renaming() const
{
const AssetCatalogTreeView &tree_view = static_cast<const AssetCatalogTreeView &>(
this->get_tree_view());
return !asset::catalogs_read_only(*tree_view.asset_library_);
}
bool AssetCatalogTreeViewItem::rename(const bContext &C, StringRefNull new_name)
{
/* Important to keep state. */
BasicTreeViewItem::rename(C, new_name);
const AssetCatalogTreeView &tree_view = static_cast<const AssetCatalogTreeView &>(
this->get_tree_view());
asset::catalog_rename(tree_view.asset_library_, catalog_item_.get_catalog_id(), new_name);
return true;
}
std::unique_ptr<ui::TreeViewItemDropTarget> AssetCatalogTreeViewItem::create_drop_target()
{
return std::make_unique<AssetCatalogDropTarget>(*this, catalog_item_);
}
std::unique_ptr<ui::AbstractViewItemDragController> AssetCatalogTreeViewItem::
create_drag_controller() const
{
return std::make_unique<AssetCatalogDragController>(
static_cast<AssetCatalogTreeView &>(this->get_tree_view()), catalog_item_);
}
/* ---------------------------------------------------------------------- */
AssetCatalogDropTarget::AssetCatalogDropTarget(AssetCatalogTreeViewItem &item,
const AssetCatalogTreeItem &catalog_item)
: ui::TreeViewItemDropTarget(item), catalog_item_(catalog_item)
{
}
bool AssetCatalogDropTarget::can_drop(const wmDrag &drag, const char **r_disabled_hint) const
{
if (drag.type == WM_DRAG_ASSET_CATALOG) {
const asset_system::AssetLibrary &library = get_asset_library();
if (!this->can_modify_catalogs(library, r_disabled_hint)) {
return false;
}
const AssetCatalog *drag_catalog = this->get_drag_catalog(drag, library);
/* NOTE: Technically it's not an issue to allow this (the catalog will just receive a new
* path and the catalog system will generate missing parents from the path). But it does
* appear broken to users, so disabling entirely. */
if (catalog_item_.catalog_path().is_contained_in(drag_catalog->path)) {
*r_disabled_hint = RPT_("Catalog cannot be dropped into itself");
return false;
}
if (catalog_item_.catalog_path() == drag_catalog->path.parent()) {
*r_disabled_hint = RPT_("Catalog is already placed inside this catalog");
return false;
}
return true;
}
if (drag.type == WM_DRAG_ASSET_LIST && has_droppable_asset(drag, r_disabled_hint)) {
return true;
}
return false;
}
std::string AssetCatalogDropTarget::drop_tooltip(const ui::DragInfo &drag_info) const
{
if (drag_info.drag_data.type == WM_DRAG_ASSET_CATALOG) {
return this->drop_tooltip_asset_catalog(drag_info.drag_data);
}
return this->drop_tooltip_asset_list(drag_info.drag_data);
}
std::string AssetCatalogDropTarget::drop_tooltip_asset_catalog(const wmDrag &drag) const
{
BLI_assert(drag.type == WM_DRAG_ASSET_CATALOG);
const AssetCatalog *src_catalog = this->get_drag_catalog(drag, get_asset_library());
return fmt::format(
TIP_("Move catalog {} into {}"), src_catalog->path.name(), catalog_item_.get_name());
}
std::string AssetCatalogDropTarget::drop_tooltip_asset_list(const wmDrag &drag) const
{
BLI_assert(drag.type == WM_DRAG_ASSET_LIST);
const ListBase *asset_drags = WM_drag_asset_list_get(&drag);
const bool is_multiple_assets = !BLI_listbase_is_single(asset_drags);
/* Don't try to be smart by dynamically adding the 's' for the plural. Just makes translation
* harder, so use full literals. */
std::string basic_tip = is_multiple_assets ? TIP_("Move assets to catalog") :
TIP_("Move asset to catalog");
basic_tip += ": " + catalog_item_.get_name();
/* Display the full catalog path, but only if it's not exactly the same as the already shown name
* (i.e. not a root level catalog with no parent). */
if (catalog_item_.get_name() != catalog_item_.catalog_path().str()) {
basic_tip += " (" + catalog_item_.catalog_path().str() + ")";
}
return basic_tip;
}
bool AssetCatalogDropTarget::on_drop(bContext *C, const ui::DragInfo &drag) const
{
if (drag.drag_data.type == WM_DRAG_ASSET_CATALOG) {
return this->drop_asset_catalog_into_catalog(
drag.drag_data, this->get_view<AssetCatalogTreeView>(), catalog_item_.get_catalog_id());
}
return this->drop_assets_into_catalog(C,
this->get_view<AssetCatalogTreeView>(),
drag.drag_data,
catalog_item_.get_catalog_id(),
catalog_item_.get_simple_name());
}
bool AssetCatalogDropTarget::drop_asset_catalog_into_catalog(
const wmDrag &drag,
AssetCatalogTreeView &tree_view,
const std::optional<CatalogID> drop_catalog_id)
{
BLI_assert(drag.type == WM_DRAG_ASSET_CATALOG);
wmDragAssetCatalog *catalog_drag = WM_drag_get_asset_catalog_data(&drag);
asset::catalog_move(tree_view.asset_library_, catalog_drag->drag_catalog_id, drop_catalog_id);
tree_view.activate_catalog_by_id(catalog_drag->drag_catalog_id);
WM_main_add_notifier(NC_ASSET | ND_ASSET_CATALOGS, nullptr);
return true;
}
bool AssetCatalogDropTarget::drop_assets_into_catalog(bContext *C,
const AssetCatalogTreeView &tree_view,
const wmDrag &drag,
CatalogID catalog_id,
StringRefNull simple_name)
{
BLI_assert(drag.type == WM_DRAG_ASSET_LIST);
const ListBase *asset_drags = WM_drag_asset_list_get(&drag);
if (!asset_drags) {
return false;
}
bool did_update = false;
LISTBASE_FOREACH (wmDragAssetListItem *, asset_item, asset_drags) {
if (asset_item->is_external) {
/* Only internal assets can be modified! */
continue;
}
did_update = true;
BKE_asset_metadata_catalog_id_set(
asset_item->asset_data.local_id->asset_data, catalog_id, simple_name.c_str());
/* Trigger re-run of filtering to update visible assets. */
filelist_tag_needs_filtering(tree_view.space_file_.files);
file_select_deselect_all(&tree_view.space_file_, FILE_SEL_SELECTED | FILE_SEL_HIGHLIGHTED);
WM_main_add_notifier(NC_SPACE | ND_SPACE_FILE_LIST, nullptr);
WM_main_add_notifier(NC_ASSET | ND_ASSET_CATALOGS, nullptr);
}
if (did_update) {
ED_undo_push(C, "Assign Asset Catalog");
}
return true;
}
AssetCatalog *AssetCatalogDropTarget::get_drag_catalog(
const wmDrag &drag, const asset_system::AssetLibrary &asset_library)
{
if (drag.type != WM_DRAG_ASSET_CATALOG) {
return nullptr;
}
const AssetCatalogService &catalog_service = asset_library.catalog_service();
const wmDragAssetCatalog *catalog_drag = WM_drag_get_asset_catalog_data(&drag);
return catalog_service.find_catalog(catalog_drag->drag_catalog_id);
}
bool AssetCatalogDropTarget::has_droppable_asset(const wmDrag &drag, const char **r_disabled_hint)
{
const ListBase *asset_drags = WM_drag_asset_list_get(&drag);
*r_disabled_hint = nullptr;
/* There needs to be at least one asset from the current file. */
LISTBASE_FOREACH (const wmDragAssetListItem *, asset_item, asset_drags) {
if (!asset_item->is_external) {
return true;
}
}
*r_disabled_hint = RPT_("Only assets from this current file can be moved between catalogs");
return false;
}
bool AssetCatalogDropTarget::can_modify_catalogs(const asset_system::AssetLibrary &library,
const char **r_disabled_hint)
{
if (asset::catalogs_read_only(library)) {
*r_disabled_hint = RPT_("Catalogs cannot be edited in this asset library");
return false;
}
return true;
}
asset_system::AssetLibrary &AssetCatalogDropTarget::get_asset_library() const
{
return *this->get_view<AssetCatalogTreeView>().asset_library_;
}
/* ---------------------------------------------------------------------- */
AssetCatalogDragController::AssetCatalogDragController(AssetCatalogTreeView &tree_view,
const AssetCatalogTreeItem &catalog_item)
: ui::AbstractViewItemDragController(tree_view), catalog_item_(catalog_item)
{
}
eWM_DragDataType AssetCatalogDragController::get_drag_type() const
{
return WM_DRAG_ASSET_CATALOG;
}
void *AssetCatalogDragController::create_drag_data() const
{
wmDragAssetCatalog *drag_catalog = (wmDragAssetCatalog *)MEM_callocN(sizeof(*drag_catalog),
__func__);
drag_catalog->drag_catalog_id = catalog_item_.get_catalog_id();
return drag_catalog;
}
void AssetCatalogDragController::on_drag_start()
{
AssetCatalogTreeView &tree_view_ = this->get_view<AssetCatalogTreeView>();
tree_view_.activate_catalog_by_id(catalog_item_.get_catalog_id());
}
/* ---------------------------------------------------------------------- */
void AssetCatalogTreeViewAllItem::build_row(uiLayout &row)
{
ui::BasicTreeViewItem::build_row(row);
PointerRNA *props;
UI_but_extra_operator_icon_add(reinterpret_cast<uiBut *>(this->view_item_button()),
"ASSET_OT_catalogs_save",
WM_OP_INVOKE_DEFAULT,
ICON_FILE_TICK);
props = UI_but_extra_operator_icon_add(reinterpret_cast<uiBut *>(this->view_item_button()),
"ASSET_OT_catalog_new",
WM_OP_INVOKE_DEFAULT,
ICON_ADD);
/* No parent path to use the root level. */
RNA_string_set(props, "parent_path", nullptr);
}
std::unique_ptr<ui::TreeViewItemDropTarget> AssetCatalogTreeViewAllItem::create_drop_target()
{
return std::make_unique<AssetCatalogTreeViewAllItem::DropTarget>(*this);
}
AssetCatalogTreeViewAllItem::DropTarget::DropTarget(AssetCatalogTreeViewAllItem &item)
: ui::TreeViewItemDropTarget(item)
{
}
bool AssetCatalogTreeViewAllItem::DropTarget::can_drop(const wmDrag &drag,
const char **r_disabled_hint) const
{
if (drag.type != WM_DRAG_ASSET_CATALOG) {
return false;
}
asset_system::AssetLibrary &library = *this->get_view<AssetCatalogTreeView>().asset_library_;
if (!AssetCatalogDropTarget::can_modify_catalogs(library, r_disabled_hint)) {
return false;
}
const AssetCatalog *drag_catalog = AssetCatalogDropTarget::get_drag_catalog(drag, library);
if (drag_catalog->path.parent() == "") {
*r_disabled_hint = RPT_("Catalog is already placed at the highest level");
return false;
}
return true;
}
std::string AssetCatalogTreeViewAllItem::DropTarget::drop_tooltip(
const ui::DragInfo &drag_info) const
{
BLI_assert(drag_info.drag_data.type == WM_DRAG_ASSET_CATALOG);
const AssetCatalog *drag_catalog = AssetCatalogDropTarget::get_drag_catalog(
drag_info.drag_data, *this->get_view<AssetCatalogTreeView>().asset_library_);
return fmt::format(TIP_("Move catalog {} to the top level of the tree"),
drag_catalog->path.name());
}
bool AssetCatalogTreeViewAllItem::DropTarget::on_drop(bContext * /*C*/,
const ui::DragInfo &drag) const
{
BLI_assert(drag.drag_data.type == WM_DRAG_ASSET_CATALOG);
return AssetCatalogDropTarget::drop_asset_catalog_into_catalog(
drag.drag_data,
this->get_view<AssetCatalogTreeView>(),
/* No value to drop into the root level. */
std::nullopt);
}
/* ---------------------------------------------------------------------- */
std::unique_ptr<ui::TreeViewItemDropTarget> AssetCatalogTreeViewUnassignedItem::
create_drop_target()
{
return std::make_unique<AssetCatalogTreeViewUnassignedItem::DropTarget>(*this);
}
AssetCatalogTreeViewUnassignedItem::DropTarget::DropTarget(
AssetCatalogTreeViewUnassignedItem &item)
: ui::TreeViewItemDropTarget(item)
{
}
bool AssetCatalogTreeViewUnassignedItem::DropTarget::can_drop(const wmDrag &drag,
const char **r_disabled_hint) const
{
if (drag.type != WM_DRAG_ASSET_LIST) {
return false;
}
return AssetCatalogDropTarget::has_droppable_asset(drag, r_disabled_hint);
}
std::string AssetCatalogTreeViewUnassignedItem::DropTarget::drop_tooltip(
const ui::DragInfo &drag_info) const
{
const ListBase *asset_drags = WM_drag_asset_list_get(&drag_info.drag_data);
const bool is_multiple_assets = !BLI_listbase_is_single(asset_drags);
return is_multiple_assets ? TIP_("Move assets out of any catalog") :
TIP_("Move asset out of any catalog");
}
bool AssetCatalogTreeViewUnassignedItem::DropTarget::on_drop(bContext *C,
const ui::DragInfo &drag) const
{
/* Assign to nil catalog ID. */
return AssetCatalogDropTarget::drop_assets_into_catalog(
C, this->get_view<AssetCatalogTreeView>(), drag.drag_data, CatalogID{});
}
/* ---------------------------------------------------------------------- */
class AssetCatalogFilterSettings {
public:
eFileSel_Params_AssetCatalogVisibility asset_catalog_visibility;
bUUID asset_catalog_id;
std::unique_ptr<AssetCatalogFilter> catalog_filter;
};
AssetCatalogFilterSettings *file_create_asset_catalog_filter_settings()
{
return MEM_new<AssetCatalogFilterSettings>(__func__);
}
void file_delete_asset_catalog_filter_settings(AssetCatalogFilterSettings **filter_settings)
{
MEM_delete(*filter_settings);
*filter_settings = nullptr;
}
bool file_set_asset_catalog_filter_settings(
AssetCatalogFilterSettings *filter_settings,
eFileSel_Params_AssetCatalogVisibility catalog_visibility,
const ::bUUID &catalog_id)
{
bool needs_update = false;
if (filter_settings->asset_catalog_visibility != catalog_visibility) {
filter_settings->asset_catalog_visibility = catalog_visibility;
needs_update = true;
}
if (filter_settings->asset_catalog_visibility == FILE_SHOW_ASSETS_FROM_CATALOG &&
!BLI_uuid_equal(filter_settings->asset_catalog_id, catalog_id))
{
filter_settings->asset_catalog_id = catalog_id;
needs_update = true;
}
return needs_update;
}
void file_ensure_updated_catalog_filter_data(AssetCatalogFilterSettings *filter_settings,
const asset_system::AssetLibrary *asset_library)
{
const AssetCatalogService &catalog_service = asset_library->catalog_service();
if (filter_settings->asset_catalog_visibility != FILE_SHOW_ASSETS_ALL_CATALOGS) {
filter_settings->catalog_filter = std::make_unique<AssetCatalogFilter>(
catalog_service.create_catalog_filter(filter_settings->asset_catalog_id));
}
}
bool file_is_asset_visible_in_catalog_filter_settings(
const AssetCatalogFilterSettings *filter_settings, const AssetMetaData *asset_data)
{
switch (filter_settings->asset_catalog_visibility) {
case FILE_SHOW_ASSETS_WITHOUT_CATALOG:
return !filter_settings->catalog_filter->is_known(asset_data->catalog_id);
case FILE_SHOW_ASSETS_FROM_CATALOG:
return filter_settings->catalog_filter->contains(asset_data->catalog_id);
case FILE_SHOW_ASSETS_ALL_CATALOGS:
/* All asset files should be visible. */
return true;
}
BLI_assert_unreachable();
return false;
}
/* ---------------------------------------------------------------------- */
void file_create_asset_catalog_tree_view_in_layout(asset_system::AssetLibrary *asset_library,
uiLayout *layout,
SpaceFile *space_file,
FileAssetSelectParams *params)
{
uiBlock *block = uiLayoutGetBlock(layout);
UI_block_layout_set_current(block, layout);
ui::AbstractTreeView *tree_view = UI_block_add_view(
*block,
"asset catalog tree view",
std::make_unique<ed::asset_browser::AssetCatalogTreeView>(
asset_library, params, *space_file));
ui::TreeViewBuilder::build_tree_view(*tree_view, *layout);
}
} // namespace blender::ed::asset_browser