From 01ab36ebc1c43764b8bfb4c41f4c837a3b8757cb Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Wed, 24 Nov 2021 17:29:43 +0100 Subject: Asset Browser: Support dragging catalogs into top level This was an oversight when I added catalog drag & drop support. I forgot to add this for dragging catalogs into the top level by dragging into to the "All" item as well. This made the drag & drop support rather broken because it wouldn't work for a basic case. --- source/blender/editors/asset/ED_asset_catalog.hh | 20 +++- .../blender/editors/asset/intern/asset_catalog.cc | 21 +++- .../editors/space_file/asset_catalog_tree_view.cc | 109 ++++++++++++++++++--- 3 files changed, 129 insertions(+), 21 deletions(-) (limited to 'source') 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 + #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 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 8e1e5be2e47..218ebe48934 100644 --- a/source/blender/editors/asset/intern/asset_catalog.cc +++ b/source/blender/editors/asset/intern/asset_catalog.cc @@ -123,7 +123,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 dst_parent_catalog_id) { bke::AssetCatalogService *catalog_service = BKE_asset_library_get_catalog_service(library); if (!catalog_service) { @@ -132,9 +132,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/space_file/asset_catalog_tree_view.cc b/source/blender/editors/space_file/asset_catalog_tree_view.cc index 41559278910..51928fa7c23 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); @@ -122,16 +127,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 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 +153,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 create_drop_controller() const override; }; class AssetCatalogTreeViewUnassignedItem : public ui::BasicTreeViewItem { @@ -228,6 +249,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) && @@ -243,11 +271,8 @@ AssetCatalogTreeViewItem::AssetCatalogTreeViewItem(AssetCatalogTreeItem *catalog void AssetCatalogTreeViewItem::on_activate() { - const AssetCatalogTreeView &tree_view = static_cast( - 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(get_tree_view()); + tree_view.activate_catalog_by_id(catalog_item_.get_catalog_id()); } void AssetCatalogTreeViewItem::build_row(uiLayout &row) @@ -344,7 +369,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. */ @@ -371,7 +396,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() + "'"; @@ -396,7 +421,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(), catalog_item_.get_catalog_id()); } return drop_assets_into_catalog(tree_view(), drag, @@ -404,12 +430,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 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; @@ -443,13 +472,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); @@ -514,6 +544,55 @@ void AssetCatalogTreeViewAllItem::build_row(uiLayout &row) RNA_string_set(props, "parent_path", nullptr); } +std::unique_ptr AssetCatalogTreeViewAllItem:: + create_drop_controller() const +{ + return std::make_unique( + static_cast(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().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().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(), + /* No value to drop into the root level. */ + std::nullopt); +} + /* ---------------------------------------------------------------------- */ std::unique_ptr AssetCatalogTreeViewUnassignedItem:: -- cgit v1.2.3 From cae3b581b05e6c1001b82773229246d48899e3d6 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Wed, 24 Nov 2021 17:59:14 +0100 Subject: Asset Browser: Fix catalog being renamed when dropping into parent When dropping catalogs it is ensured that the name of the moved catalog is unique within the new parent catalog. When dropping a catalog into the parent, the catalog would not actually move to a different location, but it would still be renamed. The unique name logic simply isn't smart enough to ignore the catalog that is about to be moved. Address this by disallowing dragging a catalog into its own parent. It's already there. --- source/blender/editors/space_file/asset_catalog_tree_view.cc | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'source') 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 51928fa7c23..5c880c15a53 100644 --- a/source/blender/editors/space_file/asset_catalog_tree_view.cc +++ b/source/blender/editors/space_file/asset_catalog_tree_view.cc @@ -377,6 +377,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) { -- cgit v1.2.3 From 71c39a9e2ef300a1ca451f1080cf59dda94ef4a4 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Wed, 24 Nov 2021 18:02:56 +0100 Subject: Asset Browser: Activate a catalog when dragging Without this it's easy to loose track of which catalog you are dragging. Things feel generally quite jumpy/disconnected, activating the catalog makes things feel far less like that. I consider this an important usability fix, therefore I'm adding it to the release branch. --- source/blender/editors/include/UI_tree_view.hh | 14 ++++++++++++++ source/blender/editors/interface/tree_view.cc | 15 +++++++++++++++ .../editors/space_file/asset_catalog_tree_view.cc | 18 ++++++++++++++---- 3 files changed, 43 insertions(+), 4 deletions(-) (limited to 'source') diff --git a/source/blender/editors/include/UI_tree_view.hh b/source/blender/editors/include/UI_tree_view.hh index 0d18eedeac9..5acee02a8cc 100644 --- a/source/blender/editors/include/UI_tree_view.hh +++ b/source/blender/editors/include/UI_tree_view.hh @@ -358,11 +358,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 inline TreeViewType &tree_view() const; }; /** @@ -453,6 +460,13 @@ inline ItemT &TreeViewItemContainer::add_tree_item(Args &&...args) add_tree_item(std::make_unique(std::forward(args)...))); } +template TreeViewType &AbstractTreeViewItemDragController::tree_view() const +{ + static_assert(std::is_base_of::value, + "Type must derive from and implement the AbstractTreeView interface"); + return static_cast(tree_view_); +} + template TreeViewType &AbstractTreeViewItemDropController::tree_view() const { static_assert(std::is_base_of::value, diff --git a/source/blender/editors/interface/tree_view.cc b/source/blender/editors/interface/tree_view.cc index fcc878c440c..488b3bbb726 100644 --- a/source/blender/editors/interface/tree_view.cc +++ b/source/blender/editors/interface/tree_view.cc @@ -550,6 +550,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) @@ -714,6 +727,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 5c880c15a53..d2d95a10c2a 100644 --- a/source/blender/editors/space_file/asset_catalog_tree_view.cc +++ b/source/blender/editors/space_file/asset_catalog_tree_view.cc @@ -110,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 { @@ -355,7 +357,8 @@ std::unique_ptr AssetCatalogTreeViewItem std::unique_ptr AssetCatalogTreeViewItem:: create_drag_controller() const { - return std::make_unique(catalog_item_); + return std::make_unique( + static_cast(get_tree_view()), catalog_item_); } /* ---------------------------------------------------------------------- */ @@ -513,8 +516,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) { } @@ -531,6 +535,12 @@ void *AssetCatalogDragController::create_drag_data() const return drag_catalog; } +void AssetCatalogDragController::on_drag_start() +{ + AssetCatalogTreeView &tree_view_ = tree_view(); + tree_view_.activate_catalog_by_id(catalog_item_.get_catalog_id()); +} + /* ---------------------------------------------------------------------- */ void AssetCatalogTreeViewAllItem::build_row(uiLayout &row) -- cgit v1.2.3