diff options
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/editors/asset/ED_asset_catalog.hh | 20 | ||||
-rw-r--r-- | source/blender/editors/asset/intern/asset_catalog.cc | 21 | ||||
-rw-r--r-- | source/blender/editors/include/UI_tree_view.hh | 14 | ||||
-rw-r--r-- | source/blender/editors/interface/tree_view.cc | 15 | ||||
-rw-r--r-- | source/blender/editors/space_file/asset_catalog_tree_view.cc | 131 |
5 files changed, 176 insertions, 25 deletions
diff --git a/source/blender/editors/asset/ED_asset_catalog.hh b/source/blender/editors/asset/ED_asset_catalog.hh index 8da8fc0d6c9..cbfce16e9eb 100644 --- a/source/blender/editors/asset/ED_asset_catalog.hh +++ b/source/blender/editors/asset/ED_asset_catalog.hh @@ -20,6 +20,8 @@ #pragma once +#include <optional> + #include "BKE_asset_catalog.hh" #include "BLI_string_ref.hh" @@ -37,6 +39,18 @@ void ED_asset_catalog_remove(AssetLibrary *library, const blender::bke::CatalogI void ED_asset_catalog_rename(AssetLibrary *library, blender::bke::CatalogID catalog_id, blender::StringRefNull new_name); -void ED_asset_catalog_move(AssetLibrary *library, - blender::bke::CatalogID src_catalog_id, - blender::bke::CatalogID dst_parent_catalog_id); +/** + * Reinsert catalog identified by \a src_catalog_id as child to catalog identified by \a + * dst_parent_catalog_id. If \a dst_parent_catalog_id is not set, the catalog is moved to the root + * level of the tree. + * The name of the reinserted catalog is made unique within the parent. Note that moving a catalog + * to the same level it was before will also change its name, since the name uniqueness check isn't + * smart enough to ignore the item to be reinserted. So the caller is expected to handle this case + * to avoid unwanted renames. + * + * Nothing is done (debug builds run into an assert) if the given catalog IDs can't be identified. + */ +void ED_asset_catalog_move( + AssetLibrary *library, + blender::bke::CatalogID src_catalog_id, + std::optional<blender::bke::CatalogID> dst_parent_catalog_id = std::nullopt); diff --git a/source/blender/editors/asset/intern/asset_catalog.cc b/source/blender/editors/asset/intern/asset_catalog.cc index 9634665be7b..787593d0a16 100644 --- a/source/blender/editors/asset/intern/asset_catalog.cc +++ b/source/blender/editors/asset/intern/asset_catalog.cc @@ -122,7 +122,7 @@ void ED_asset_catalog_rename(::AssetLibrary *library, void ED_asset_catalog_move(::AssetLibrary *library, const CatalogID src_catalog_id, - const CatalogID dst_parent_catalog_id) + const std::optional<CatalogID> dst_parent_catalog_id) { bke::AssetCatalogService *catalog_service = BKE_asset_library_get_catalog_service(library); if (!catalog_service) { @@ -131,9 +131,24 @@ void ED_asset_catalog_move(::AssetLibrary *library, } AssetCatalog *src_catalog = catalog_service->find_catalog(src_catalog_id); - AssetCatalog *dst_catalog = catalog_service->find_catalog(dst_parent_catalog_id); + if (!src_catalog) { + BLI_assert_unreachable(); + return; + } + AssetCatalog *dst_catalog = dst_parent_catalog_id ? + catalog_service->find_catalog(*dst_parent_catalog_id) : + nullptr; + if (!dst_catalog && dst_parent_catalog_id) { + BLI_assert_unreachable(); + return; + } - const AssetCatalogPath new_path = dst_catalog->path / StringRef(src_catalog->path.name()); + std::string unique_name = catalog_name_ensure_unique( + *catalog_service, src_catalog->path.name(), dst_catalog ? dst_catalog->path.c_str() : ""); + /* If a destination catalog was given, construct the path using that. Otherwise, the path is just + * the name of the catalog to be moved, which means it ends up at the root level. */ + const AssetCatalogPath new_path = dst_catalog ? (dst_catalog->path / unique_name) : + AssetCatalogPath{unique_name}; const AssetCatalogPath clean_new_path = new_path.cleanup(); if (new_path == src_catalog->path || clean_new_path == src_catalog->path) { diff --git a/source/blender/editors/include/UI_tree_view.hh b/source/blender/editors/include/UI_tree_view.hh index 8caf17741a7..7682570a5c6 100644 --- a/source/blender/editors/include/UI_tree_view.hh +++ b/source/blender/editors/include/UI_tree_view.hh @@ -360,11 +360,18 @@ class AbstractTreeViewItem : public TreeViewItemContainer { * custom implementation of #AbstractTreeViewItem::create_drag_controller(). */ class AbstractTreeViewItemDragController { + protected: + AbstractTreeView &tree_view_; + public: + AbstractTreeViewItemDragController(AbstractTreeView &tree_view); virtual ~AbstractTreeViewItemDragController() = default; virtual int get_drag_type() const = 0; virtual void *create_drag_data() const = 0; + virtual void on_drag_start(); + + template<class TreeViewType> inline TreeViewType &tree_view() const; }; /** @@ -463,6 +470,13 @@ inline ItemT &TreeViewItemContainer::add_tree_item(Args &&...args) add_tree_item(std::make_unique<ItemT>(std::forward<Args>(args)...))); } +template<class TreeViewType> TreeViewType &AbstractTreeViewItemDragController::tree_view() const +{ + static_assert(std::is_base_of<AbstractTreeView, TreeViewType>::value, + "Type must derive from and implement the AbstractTreeView interface"); + return static_cast<TreeViewType &>(tree_view_); +} + template<class TreeViewType> TreeViewType &AbstractTreeViewItemDropController::tree_view() const { static_assert(std::is_base_of<AbstractTreeView, TreeViewType>::value, diff --git a/source/blender/editors/interface/tree_view.cc b/source/blender/editors/interface/tree_view.cc index 5fcf78dd565..3ed027ddd9d 100644 --- a/source/blender/editors/interface/tree_view.cc +++ b/source/blender/editors/interface/tree_view.cc @@ -562,6 +562,19 @@ void AbstractTreeViewItem::change_state_delayed() activate(); } } + +/* ---------------------------------------------------------------------- */ + +AbstractTreeViewItemDragController::AbstractTreeViewItemDragController(AbstractTreeView &tree_view) + : tree_view_(tree_view) +{ +} + +void AbstractTreeViewItemDragController::on_drag_start() +{ + /* Do nothing by default. */ +} + /* ---------------------------------------------------------------------- */ AbstractTreeViewItemDropController::AbstractTreeViewItemDropController(AbstractTreeView &tree_view) @@ -739,6 +752,8 @@ bool UI_tree_view_item_drag_start(bContext *C, uiTreeViewItemHandle *item_) drag_controller->create_drag_data(), 0, WM_DRAG_FREE_DATA); + drag_controller->on_drag_start(); + return true; } diff --git a/source/blender/editors/space_file/asset_catalog_tree_view.cc b/source/blender/editors/space_file/asset_catalog_tree_view.cc index dee5168e30b..35c671e8ea5 100644 --- a/source/blender/editors/space_file/asset_catalog_tree_view.cc +++ b/source/blender/editors/space_file/asset_catalog_tree_view.cc @@ -52,6 +52,8 @@ using namespace blender::bke; namespace blender::ed::asset_browser { +class AssetCatalogTreeViewAllItem; + class AssetCatalogTreeView : public ui::AbstractTreeView { ::AssetLibrary *asset_library_; /** The asset catalog tree this tree-view represents. */ @@ -61,6 +63,7 @@ class AssetCatalogTreeView : public ui::AbstractTreeView { friend class AssetCatalogTreeViewItem; friend class AssetCatalogDropController; + friend class AssetCatalogTreeViewAllItem; public: AssetCatalogTreeView(::AssetLibrary *library, @@ -69,6 +72,8 @@ class AssetCatalogTreeView : public ui::AbstractTreeView { void build_tree() override; + void activate_catalog_by_id(CatalogID catalog_id); + private: ui::BasicTreeViewItem &build_catalog_items_recursive(ui::TreeViewItemContainer &view_parent_item, AssetCatalogTreeItem &catalog); @@ -105,10 +110,12 @@ class AssetCatalogDragController : public ui::AbstractTreeViewItemDragController AssetCatalogTreeItem &catalog_item_; public: - explicit AssetCatalogDragController(AssetCatalogTreeItem &catalog_item); + explicit AssetCatalogDragController(AssetCatalogTreeView &tree_view, + AssetCatalogTreeItem &catalog_item); int get_drag_type() const override; void *create_drag_data() const override; + void on_drag_start() override; }; class AssetCatalogDropController : public ui::AbstractTreeViewItemDropController { @@ -122,16 +129,22 @@ class AssetCatalogDropController : public ui::AbstractTreeViewItemDropController bool on_drop(const wmDrag &drag) override; ::AssetLibrary &get_asset_library() const; - AssetCatalog *get_drag_catalog(const wmDrag &drag) const; + static AssetCatalog *get_drag_catalog(const wmDrag &drag, const ::AssetLibrary &asset_library); static bool has_droppable_asset(const wmDrag &drag, const char **r_disabled_hint); static bool drop_assets_into_catalog(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: - bool drop_asset_catalog_into_catalog(const wmDrag &drag); std::string drop_tooltip_asset_list(const wmDrag &drag) const; std::string drop_tooltip_asset_catalog(const wmDrag &drag) const; }; @@ -142,6 +155,16 @@ class AssetCatalogTreeViewAllItem : public ui::BasicTreeViewItem { using BasicTreeViewItem::BasicTreeViewItem; void build_row(uiLayout &row) override; + + struct DropController : public ui::AbstractTreeViewItemDropController { + DropController(AssetCatalogTreeView &tree_view); + + bool can_drop(const wmDrag &drag, const char **r_disabled_hint) const override; + std::string drop_tooltip(const wmDrag &drag) const override; + bool on_drop(const wmDrag &drag) override; + }; + + std::unique_ptr<ui::AbstractTreeViewItemDropController> create_drop_controller() const override; }; class AssetCatalogTreeViewUnassignedItem : public ui::BasicTreeViewItem { @@ -229,6 +252,13 @@ void AssetCatalogTreeView::add_unassigned_item() [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) && @@ -244,11 +274,8 @@ AssetCatalogTreeViewItem::AssetCatalogTreeViewItem(AssetCatalogTreeItem *catalog void AssetCatalogTreeViewItem::on_activate() { - const AssetCatalogTreeView &tree_view = static_cast<const AssetCatalogTreeView &>( - get_tree_view()); - tree_view.params_->asset_catalog_visibility = FILE_SHOW_ASSETS_FROM_CATALOG; - tree_view.params_->catalog_id = catalog_item_.get_catalog_id(); - WM_main_add_notifier(NC_SPACE | ND_SPACE_ASSET_PARAMS, nullptr); + 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) @@ -331,7 +358,8 @@ std::unique_ptr<ui::AbstractTreeViewItemDropController> AssetCatalogTreeViewItem std::unique_ptr<ui::AbstractTreeViewItemDragController> AssetCatalogTreeViewItem:: create_drag_controller() const { - return std::make_unique<AssetCatalogDragController>(catalog_item_); + return std::make_unique<AssetCatalogDragController>( + static_cast<AssetCatalogTreeView &>(get_tree_view()), catalog_item_); } /* ---------------------------------------------------------------------- */ @@ -345,7 +373,7 @@ AssetCatalogDropController::AssetCatalogDropController(AssetCatalogTreeView &tre bool AssetCatalogDropController::can_drop(const wmDrag &drag, const char **r_disabled_hint) const { if (drag.type == WM_DRAG_ASSET_CATALOG) { - const AssetCatalog *drag_catalog = get_drag_catalog(drag); + const AssetCatalog *drag_catalog = get_drag_catalog(drag, get_asset_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. */ @@ -353,6 +381,10 @@ bool AssetCatalogDropController::can_drop(const wmDrag &drag, const char **r_dis *r_disabled_hint = "Catalog cannot be dropped into itself"; return false; } + if (catalog_item_.catalog_path() == drag_catalog->path.parent()) { + *r_disabled_hint = "Catalog is already placed inside this catalog"; + return false; + } return true; } if (drag.type == WM_DRAG_ASSET_LIST) { @@ -372,7 +404,7 @@ std::string AssetCatalogDropController::drop_tooltip(const wmDrag &drag) const std::string AssetCatalogDropController::drop_tooltip_asset_catalog(const wmDrag &drag) const { BLI_assert(drag.type == WM_DRAG_ASSET_CATALOG); - const AssetCatalog *src_catalog = get_drag_catalog(drag); + const AssetCatalog *src_catalog = get_drag_catalog(drag, get_asset_library()); return std::string(TIP_("Move Catalog")) + " '" + src_catalog->path.name() + "' " + TIP_("into") + " '" + catalog_item_.get_name() + "'"; @@ -397,7 +429,8 @@ std::string AssetCatalogDropController::drop_tooltip_asset_list(const wmDrag &dr bool AssetCatalogDropController::on_drop(const wmDrag &drag) { if (drag.type == WM_DRAG_ASSET_CATALOG) { - return drop_asset_catalog_into_catalog(drag); + return drop_asset_catalog_into_catalog( + drag, tree_view<AssetCatalogTreeView>(), catalog_item_.get_catalog_id()); } return drop_assets_into_catalog(tree_view<AssetCatalogTreeView>(), drag, @@ -405,12 +438,15 @@ bool AssetCatalogDropController::on_drop(const wmDrag &drag) catalog_item_.get_simple_name()); } -bool AssetCatalogDropController::drop_asset_catalog_into_catalog(const wmDrag &drag) +bool AssetCatalogDropController::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); - ED_asset_catalog_move( - &get_asset_library(), catalog_drag->drag_catalog_id, catalog_item_.get_catalog_id()); + ED_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; @@ -444,13 +480,14 @@ bool AssetCatalogDropController::drop_assets_into_catalog(const AssetCatalogTree return true; } -AssetCatalog *AssetCatalogDropController::get_drag_catalog(const wmDrag &drag) const +AssetCatalog *AssetCatalogDropController::get_drag_catalog(const wmDrag &drag, + const ::AssetLibrary &asset_library) { if (drag.type != WM_DRAG_ASSET_CATALOG) { return nullptr; } const bke::AssetCatalogService *catalog_service = BKE_asset_library_get_catalog_service( - &get_asset_library()); + &asset_library); const wmDragAssetCatalog *catalog_drag = WM_drag_get_asset_catalog_data(&drag); return catalog_service->find_catalog(catalog_drag->drag_catalog_id); @@ -480,8 +517,9 @@ bool AssetCatalogDropController::has_droppable_asset(const wmDrag &drag, /* ---------------------------------------------------------------------- */ -AssetCatalogDragController::AssetCatalogDragController(AssetCatalogTreeItem &catalog_item) - : catalog_item_(catalog_item) +AssetCatalogDragController::AssetCatalogDragController(AssetCatalogTreeView &tree_view, + AssetCatalogTreeItem &catalog_item) + : ui::AbstractTreeViewItemDragController(tree_view), catalog_item_(catalog_item) { } @@ -498,6 +536,12 @@ void *AssetCatalogDragController::create_drag_data() const return drag_catalog; } +void AssetCatalogDragController::on_drag_start() +{ + AssetCatalogTreeView &tree_view_ = tree_view<AssetCatalogTreeView>(); + tree_view_.activate_catalog_by_id(catalog_item_.get_catalog_id()); +} + /* ---------------------------------------------------------------------- */ void AssetCatalogTreeViewAllItem::build_row(uiLayout &row) @@ -515,6 +559,55 @@ void AssetCatalogTreeViewAllItem::build_row(uiLayout &row) RNA_string_set(props, "parent_path", nullptr); } +std::unique_ptr<ui::AbstractTreeViewItemDropController> AssetCatalogTreeViewAllItem:: + create_drop_controller() const +{ + return std::make_unique<AssetCatalogTreeViewAllItem::DropController>( + static_cast<AssetCatalogTreeView &>(get_tree_view())); +} + +AssetCatalogTreeViewAllItem::DropController::DropController(AssetCatalogTreeView &tree_view) + : ui::AbstractTreeViewItemDropController(tree_view) +{ +} + +bool AssetCatalogTreeViewAllItem::DropController::can_drop(const wmDrag &drag, + const char **r_disabled_hint) const +{ + if (drag.type != WM_DRAG_ASSET_CATALOG) { + return false; + } + + const AssetCatalog *drag_catalog = AssetCatalogDropController::get_drag_catalog( + drag, *tree_view<AssetCatalogTreeView>().asset_library_); + if (drag_catalog->path.parent() == "") { + *r_disabled_hint = "Catalog is already placed at the highest level"; + return false; + } + + return true; +} + +std::string AssetCatalogTreeViewAllItem::DropController::drop_tooltip(const wmDrag &drag) const +{ + BLI_assert(drag.type == WM_DRAG_ASSET_CATALOG); + const AssetCatalog *drag_catalog = AssetCatalogDropController::get_drag_catalog( + drag, *tree_view<AssetCatalogTreeView>().asset_library_); + + return std::string(TIP_("Move Catalog")) + " '" + drag_catalog->path.name() + "' " + + TIP_("to the top level of the tree"); +} + +bool AssetCatalogTreeViewAllItem::DropController::on_drop(const wmDrag &drag) +{ + BLI_assert(drag.type == WM_DRAG_ASSET_CATALOG); + return AssetCatalogDropController::drop_asset_catalog_into_catalog( + drag, + tree_view<AssetCatalogTreeView>(), + /* No value to drop into the root level. */ + std::nullopt); +} + /* ---------------------------------------------------------------------- */ std::unique_ptr<ui::AbstractTreeViewItemDropController> AssetCatalogTreeViewUnassignedItem:: |