Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenkernel/BKE_asset_library.hh4
-rw-r--r--source/blender/blenkernel/intern/asset_library.cc23
-rw-r--r--source/blender/editors/asset/CMakeLists.txt2
-rw-r--r--source/blender/editors/asset/ED_asset_catalog.hh35
-rw-r--r--source/blender/editors/asset/intern/asset_catalog.cc87
-rw-r--r--source/blender/editors/asset/intern/asset_ops.cc88
-rw-r--r--source/blender/editors/include/ED_fileselect.h1
-rw-r--r--source/blender/editors/include/UI_interface.h3
-rw-r--r--source/blender/editors/include/UI_tree_view.hh6
-rw-r--r--source/blender/editors/interface/interface.c9
-rw-r--r--source/blender/editors/interface/tree_view.cc19
-rw-r--r--source/blender/editors/space_file/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_file/asset_catalog_tree_view.cc230
-rw-r--r--source/blender/editors/space_file/file_intern.h10
-rw-r--r--source/blender/editors/space_file/file_panels.c32
-rw-r--r--source/blender/editors/space_file/filelist.c52
-rw-r--r--source/blender/editors/space_file/filelist.h7
-rw-r--r--source/blender/editors/space_file/filesel.c14
-rw-r--r--source/blender/editors/space_file/space_file.c9
-rw-r--r--source/blender/makesdna/DNA_space_types.h15
-rw-r--r--source/blender/makesrna/intern/rna_space.c62
21 files changed, 636 insertions, 73 deletions
diff --git a/source/blender/blenkernel/BKE_asset_library.hh b/source/blender/blenkernel/BKE_asset_library.hh
index fc5e137dd3e..1dc02f7aa9b 100644
--- a/source/blender/blenkernel/BKE_asset_library.hh
+++ b/source/blender/blenkernel/BKE_asset_library.hh
@@ -48,3 +48,7 @@ struct AssetLibrary {
};
} // namespace blender::bke
+
+blender::bke::AssetCatalogService *BKE_asset_library_get_catalog_service(
+ const ::AssetLibrary *library);
+blender::bke::AssetCatalogTree *BKE_asset_library_get_catalog_tree(const ::AssetLibrary *library);
diff --git a/source/blender/blenkernel/intern/asset_library.cc b/source/blender/blenkernel/intern/asset_library.cc
index 1086efe45fd..27e66ee5725 100644
--- a/source/blender/blenkernel/intern/asset_library.cc
+++ b/source/blender/blenkernel/intern/asset_library.cc
@@ -68,6 +68,29 @@ bool BKE_asset_library_find_suitable_root_path_from_main(const Main *bmain, char
return BKE_asset_library_find_suitable_root_path_from_path(bmain->name, r_library_path);
}
+blender::bke::AssetCatalogService *BKE_asset_library_get_catalog_service(
+ const ::AssetLibrary *library_c)
+{
+ if (library_c == nullptr) {
+ return nullptr;
+ }
+
+ const blender::bke::AssetLibrary &library = reinterpret_cast<const blender::bke::AssetLibrary &>(
+ *library_c);
+ return library.catalog_service.get();
+}
+
+blender::bke::AssetCatalogTree *BKE_asset_library_get_catalog_tree(const ::AssetLibrary *library)
+{
+ blender::bke::AssetCatalogService *catalog_service = BKE_asset_library_get_catalog_service(
+ library);
+ if (catalog_service == nullptr) {
+ return nullptr;
+ }
+
+ return catalog_service->get_catalog_tree();
+}
+
namespace blender::bke {
void AssetLibrary::load(StringRefNull library_root_directory)
diff --git a/source/blender/editors/asset/CMakeLists.txt b/source/blender/editors/asset/CMakeLists.txt
index 31c07580570..b6657bfca63 100644
--- a/source/blender/editors/asset/CMakeLists.txt
+++ b/source/blender/editors/asset/CMakeLists.txt
@@ -31,6 +31,7 @@ set(INC_SYS
)
set(SRC
+ intern/asset_catalog.cc
intern/asset_filter.cc
intern/asset_handle.cc
intern/asset_library_reference.cc
@@ -40,6 +41,7 @@ set(SRC
intern/asset_ops.cc
intern/asset_temp_id_consumer.cc
+ ED_asset_catalog.hh
ED_asset_filter.h
ED_asset_handle.h
ED_asset_library.h
diff --git a/source/blender/editors/asset/ED_asset_catalog.hh b/source/blender/editors/asset/ED_asset_catalog.hh
new file mode 100644
index 00000000000..cffd7728a60
--- /dev/null
+++ b/source/blender/editors/asset/ED_asset_catalog.hh
@@ -0,0 +1,35 @@
+/*
+ * 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
+ */
+
+#pragma once
+
+#include "BKE_asset_catalog.hh"
+
+#include "BLI_string_ref.hh"
+
+struct AssetLibrary;
+namespace blender::bke {
+class AssetCatalog;
+} // namespace blender::bke
+
+blender::bke::AssetCatalog *ED_asset_catalog_add(AssetLibrary *library,
+ blender::StringRefNull name,
+ blender::StringRef parent_path = nullptr);
+void ED_asset_catalog_remove(AssetLibrary *library, const blender::bke::CatalogID &catalog_id);
diff --git a/source/blender/editors/asset/intern/asset_catalog.cc b/source/blender/editors/asset/intern/asset_catalog.cc
new file mode 100644
index 00000000000..202d4234051
--- /dev/null
+++ b/source/blender/editors/asset/intern/asset_catalog.cc
@@ -0,0 +1,87 @@
+/*
+ * 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_asset_catalog.hh"
+#include "BKE_asset_library.hh"
+
+#include "BLI_string_utils.h"
+
+#include "ED_asset_catalog.hh"
+
+using namespace blender;
+using namespace blender::bke;
+
+struct CatalogUniqueNameFnData {
+ const AssetCatalogService &catalog_service;
+ StringRef parent_path;
+};
+
+static std::string to_full_path(StringRef parent_path, StringRef name)
+{
+ return parent_path.is_empty() ?
+ std::string(name) :
+ std::string(parent_path) + AssetCatalogService::PATH_SEPARATOR + name;
+}
+
+static bool catalog_name_exists_fn(void *arg, const char *name)
+{
+ CatalogUniqueNameFnData &fn_data = *static_cast<CatalogUniqueNameFnData *>(arg);
+ std::string fullpath = to_full_path(fn_data.parent_path, name);
+ return fn_data.catalog_service.find_catalog_by_path(fullpath);
+}
+
+static std::string catalog_name_ensure_unique(AssetCatalogService &catalog_service,
+ StringRefNull name,
+ StringRef parent_path)
+{
+ CatalogUniqueNameFnData fn_data = {catalog_service, parent_path};
+
+ char unique_name[NAME_MAX] = "";
+ BLI_uniquename_cb(
+ catalog_name_exists_fn, &fn_data, name.c_str(), '.', unique_name, sizeof(unique_name));
+
+ return unique_name;
+}
+
+AssetCatalog *ED_asset_catalog_add(::AssetLibrary *library,
+ StringRefNull name,
+ StringRef parent_path)
+{
+ bke::AssetCatalogService *catalog_service = BKE_asset_library_get_catalog_service(library);
+ if (!catalog_service) {
+ return nullptr;
+ }
+
+ std::string unique_name = catalog_name_ensure_unique(*catalog_service, name, parent_path);
+ std::string fullpath = to_full_path(parent_path, unique_name);
+
+ return catalog_service->create_catalog(fullpath);
+}
+
+void ED_asset_catalog_remove(::AssetLibrary *library, const CatalogID &catalog_id)
+{
+ bke::AssetCatalogService *catalog_service = BKE_asset_library_get_catalog_service(library);
+ if (!catalog_service) {
+ BLI_assert_unreachable();
+ return;
+ }
+
+ catalog_service->delete_catalog(catalog_id);
+}
diff --git a/source/blender/editors/asset/intern/asset_ops.cc b/source/blender/editors/asset/intern/asset_ops.cc
index a18b7649060..5424bae77b4 100644
--- a/source/blender/editors/asset/intern/asset_ops.cc
+++ b/source/blender/editors/asset/intern/asset_ops.cc
@@ -18,13 +18,18 @@
* \ingroup edasset
*/
+#include "BKE_asset_catalog.hh"
#include "BKE_context.h"
#include "BKE_lib_id.h"
#include "BKE_report.h"
+#include "BLI_string_ref.hh"
#include "BLI_vector.hh"
#include "ED_asset.h"
+#include "ED_asset_catalog.hh"
+/* XXX needs access to the file list, should all be done via the asset system in future. */
+#include "ED_fileselect.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -32,6 +37,8 @@
#include "WM_api.h"
#include "WM_types.h"
+using namespace blender;
+
/* -------------------------------------------------------------------- */
using PointerRNAVec = blender::Vector<PointerRNA>;
@@ -372,10 +379,91 @@ static void ASSET_OT_list_refresh(struct wmOperatorType *ot)
/* -------------------------------------------------------------------- */
+static bool asset_catalog_operator_poll(bContext *C)
+{
+ const SpaceFile *sfile = CTX_wm_space_file(C);
+ return asset_operation_poll(C) && sfile && ED_fileselect_active_asset_library_get(sfile);
+}
+
+static int asset_catalog_new_exec(bContext *C, wmOperator *op)
+{
+ SpaceFile *sfile = CTX_wm_space_file(C);
+ struct AssetLibrary *asset_library = ED_fileselect_active_asset_library_get(sfile);
+ char *parent_path = RNA_string_get_alloc(op->ptr, "parent_path", nullptr, 0, nullptr);
+
+ ED_asset_catalog_add(asset_library, "Catalog", parent_path);
+
+ MEM_freeN(parent_path);
+
+ WM_main_add_notifier(NC_SPACE | ND_SPACE_ASSET_PARAMS, nullptr);
+
+ return OPERATOR_FINISHED;
+}
+
+static void ASSET_OT_catalog_new(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "New Asset Catalog";
+ ot->description = "Create a new catalog to put assets in";
+ ot->idname = "ASSET_OT_catalog_new";
+
+ /* api callbacks */
+ ot->exec = asset_catalog_new_exec;
+ ot->poll = asset_catalog_operator_poll;
+
+ RNA_def_string(ot->srna,
+ "parent_path",
+ nullptr,
+ 0,
+ "Parent Path",
+ "Optional path defining the location to put the new catalog under");
+}
+
+static int asset_catalog_delete_exec(bContext *C, wmOperator *op)
+{
+ SpaceFile *sfile = CTX_wm_space_file(C);
+ struct AssetLibrary *asset_library = ED_fileselect_active_asset_library_get(sfile);
+ char *catalog_id_str = RNA_string_get_alloc(op->ptr, "catalog_id", nullptr, 0, nullptr);
+ bke::CatalogID catalog_id;
+ if (!BLI_uuid_parse_string(&catalog_id, catalog_id_str)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ ED_asset_catalog_remove(asset_library, catalog_id);
+
+ MEM_freeN(catalog_id_str);
+
+ WM_main_add_notifier(NC_SPACE | ND_SPACE_ASSET_PARAMS, nullptr);
+
+ return OPERATOR_FINISHED;
+}
+
+static void ASSET_OT_catalog_delete(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Delete Asset Catalog";
+ ot->description =
+ "Remove an asset catalog from the asset library (contained assets will not be affected and "
+ "show up as unassigned)";
+ ot->idname = "ASSET_OT_catalog_delete";
+
+ /* api callbacks */
+ ot->exec = asset_catalog_delete_exec;
+ ot->invoke = WM_operator_confirm;
+ ot->poll = asset_catalog_operator_poll;
+
+ RNA_def_string(ot->srna, "catalog_id", nullptr, 0, "Catalog ID", "ID of the catalog to delete");
+}
+
+/* -------------------------------------------------------------------- */
+
void ED_operatortypes_asset(void)
{
WM_operatortype_append(ASSET_OT_mark);
WM_operatortype_append(ASSET_OT_clear);
+ WM_operatortype_append(ASSET_OT_catalog_new);
+ WM_operatortype_append(ASSET_OT_catalog_delete);
+
WM_operatortype_append(ASSET_OT_list_refresh);
}
diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h
index 82057c726a5..423d619f41a 100644
--- a/source/blender/editors/include/ED_fileselect.h
+++ b/source/blender/editors/include/ED_fileselect.h
@@ -142,6 +142,7 @@ void ED_fileselect_exit(struct wmWindowManager *wm, struct SpaceFile *sfile);
bool ED_fileselect_is_file_browser(const struct SpaceFile *sfile);
bool ED_fileselect_is_asset_browser(const struct SpaceFile *sfile);
+struct AssetLibrary *ED_fileselect_active_asset_library_get(const struct SpaceFile *sfile);
struct ID *ED_fileselect_active_asset_get(const struct SpaceFile *sfile);
/* Activate the file that corresponds to the given ID.
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index f7842270746..106f6166760 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -2761,7 +2761,8 @@ void UI_interface_tag_script_reload(void);
/* Support click-drag motion which presses the button and closes a popover (like a menu). */
#define USE_UI_POPOVER_ONCE
-bool UI_tree_view_item_is_active(uiTreeViewItemHandle *item_);
+bool UI_tree_view_item_is_active(const uiTreeViewItemHandle *item);
+bool UI_tree_view_item_matches(const uiTreeViewItemHandle *a, const uiTreeViewItemHandle *b);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/include/UI_tree_view.hh b/source/blender/editors/include/UI_tree_view.hh
index fac880a0a67..81a614cd195 100644
--- a/source/blender/editors/include/UI_tree_view.hh
+++ b/source/blender/editors/include/UI_tree_view.hh
@@ -190,6 +190,12 @@ class AbstractTreeViewItem : public TreeViewItemContainer {
* last redraw to this item. If sub-classes introduce more advanced state they should override
* this and make it update their state accordingly. */
virtual void update_from_old(const AbstractTreeViewItem &old);
+ /** Compare this item to \a other to check if they represent the same data. This is critical for
+ * being able to recognize an item from a previous redraw, to be able to keep its state (e.g.
+ * open/closed, active, etc.). Items are only matched if their parents also match.
+ * By default this just matches the items names/labels (if their parents match!). If that isn't
+ * good enough for a sub-class, that can override it. */
+ virtual bool matches(const AbstractTreeViewItem &other) const;
const AbstractTreeView &get_tree_view() const;
int count_parents() const;
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index a98af00572d..c53bffca778 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -743,6 +743,15 @@ static bool ui_but_equals_old(const uiBut *but, const uiBut *oldbut)
return false;
}
+ if ((but->type == UI_BTYPE_TREEROW) && (oldbut->type == UI_BTYPE_TREEROW)) {
+ uiButTreeRow *but_treerow = (uiButTreeRow *)but;
+ uiButTreeRow *oldbut_treerow = (uiButTreeRow *)oldbut;
+ if (!but_treerow->tree_item || !oldbut_treerow->tree_item ||
+ !UI_tree_view_item_matches(but_treerow->tree_item, oldbut_treerow->tree_item)) {
+ return false;
+ }
+ }
+
return true;
}
diff --git a/source/blender/editors/interface/tree_view.cc b/source/blender/editors/interface/tree_view.cc
index ee50126f974..16499065019 100644
--- a/source/blender/editors/interface/tree_view.cc
+++ b/source/blender/editors/interface/tree_view.cc
@@ -123,7 +123,7 @@ AbstractTreeViewItem *AbstractTreeView::find_matching_child(
const AbstractTreeViewItem &lookup_item, const TreeViewItemContainer &items)
{
for (const auto &iter_item : items.children_) {
- if (lookup_item.label_ == iter_item->label_) {
+ if (lookup_item.matches(*iter_item)) {
/* We have a matching item! */
return iter_item.get();
}
@@ -145,6 +145,11 @@ void AbstractTreeViewItem::update_from_old(const AbstractTreeViewItem &old)
is_active_ = old.is_active_;
}
+bool AbstractTreeViewItem::matches(const AbstractTreeViewItem &other) const
+{
+ return label_ == other.label_;
+}
+
const AbstractTreeView &AbstractTreeViewItem::get_tree_view() const
{
return static_cast<AbstractTreeView &>(*root_);
@@ -309,8 +314,16 @@ uiBut *BasicTreeViewItem::button()
using namespace blender::ui;
-bool UI_tree_view_item_is_active(uiTreeViewItemHandle *item_)
+bool UI_tree_view_item_is_active(const uiTreeViewItemHandle *item_handle)
{
- AbstractTreeViewItem &item = reinterpret_cast<AbstractTreeViewItem &>(*item_);
+ const AbstractTreeViewItem &item = reinterpret_cast<const AbstractTreeViewItem &>(*item_handle);
return item.is_active();
}
+
+bool UI_tree_view_item_matches(const uiTreeViewItemHandle *a_handle,
+ const uiTreeViewItemHandle *b_handle)
+{
+ const AbstractTreeViewItem &a = reinterpret_cast<const AbstractTreeViewItem &>(*a_handle);
+ const AbstractTreeViewItem &b = reinterpret_cast<const AbstractTreeViewItem &>(*b_handle);
+ return a.matches(b);
+}
diff --git a/source/blender/editors/space_file/CMakeLists.txt b/source/blender/editors/space_file/CMakeLists.txt
index b60f9df82f6..4b508f16c1e 100644
--- a/source/blender/editors/space_file/CMakeLists.txt
+++ b/source/blender/editors/space_file/CMakeLists.txt
@@ -34,6 +34,7 @@ set(INC
)
set(SRC
+ asset_catalog_tree_view.cc
file_draw.c
file_ops.c
file_panels.c
diff --git a/source/blender/editors/space_file/asset_catalog_tree_view.cc b/source/blender/editors/space_file/asset_catalog_tree_view.cc
new file mode 100644
index 00000000000..7eea9af925b
--- /dev/null
+++ b/source/blender/editors/space_file/asset_catalog_tree_view.cc
@@ -0,0 +1,230 @@
+/*
+ * 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.
+ *
+ * The Original Code is Copyright (C) 2007 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup spfile
+ */
+
+#include "ED_fileselect.h"
+
+#include "DNA_space_types.h"
+
+#include "BKE_asset_catalog.hh"
+#include "BKE_asset_library.hh"
+
+#include "BLI_string_ref.hh"
+
+#include "BLT_translation.h"
+
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_interface.hh"
+#include "UI_resources.h"
+#include "UI_tree_view.hh"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "file_intern.h"
+
+using namespace blender;
+using namespace blender::bke;
+
+namespace blender::ed::asset_browser {
+
+class AssetCatalogTreeView : public ui::AbstractTreeView {
+ /** The asset catalog tree this tree-view represents. */
+ bke::AssetCatalogTree *catalog_tree_;
+ FileAssetSelectParams *params_;
+
+ friend class AssetCatalogTreeViewItem;
+
+ public:
+ AssetCatalogTreeView(::AssetLibrary *library, FileAssetSelectParams *params);
+
+ void build_tree() override;
+
+ private:
+ ui::BasicTreeViewItem &build_catalog_items_recursive(ui::TreeViewItemContainer &view_parent_item,
+ AssetCatalogTreeItem &catalog);
+
+ void 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. */
+ AssetCatalogTreeItem &catalog_item_;
+
+ public:
+ AssetCatalogTreeViewItem(AssetCatalogTreeItem *catalog_item)
+ : BasicTreeViewItem(catalog_item->get_name()), catalog_item_(*catalog_item)
+ {
+ }
+
+ void on_activate() override
+ {
+ 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);
+ }
+
+ void build_row(uiLayout &row) override
+ {
+ ui::BasicTreeViewItem::build_row(row);
+
+ if (!is_active()) {
+ return;
+ }
+
+ PointerRNA *props;
+ const CatalogID catalog_id = catalog_item_.get_catalog_id();
+
+ props = UI_but_extra_operator_icon_add(
+ button(), "ASSET_OT_catalog_new", WM_OP_INVOKE_DEFAULT, ICON_ADD);
+ RNA_string_set(props, "parent_path", catalog_item_.catalog_path().c_str());
+
+ /* Tree items without a catalog ID represent components of catalog paths that are not
+ * associated with an actual catalog. They exist merely by the presence of a child catalog, and
+ * thus cannot be deleted themselves. */
+ if (!BLI_uuid_is_nil(catalog_id)) {
+ char catalog_id_str_buffer[UUID_STRING_LEN] = "";
+ BLI_uuid_format(catalog_id_str_buffer, catalog_id);
+
+ props = UI_but_extra_operator_icon_add(
+ button(), "ASSET_OT_catalog_delete", WM_OP_INVOKE_DEFAULT, ICON_X);
+ RNA_string_set(props, "catalog_id", catalog_id_str_buffer);
+ }
+ }
+};
+
+/** 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
+ {
+ ui::BasicTreeViewItem::build_row(row);
+
+ if (!is_active()) {
+ return;
+ }
+
+ PointerRNA *props;
+ props = UI_but_extra_operator_icon_add(
+ 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);
+ }
+};
+
+AssetCatalogTreeView::AssetCatalogTreeView(::AssetLibrary *library, FileAssetSelectParams *params)
+ : catalog_tree_(BKE_asset_library_get_catalog_tree(library)), params_(params)
+{
+}
+
+void AssetCatalogTreeView::build_tree()
+{
+ add_all_item();
+
+ if (catalog_tree_) {
+ catalog_tree_->foreach_root_item([this](AssetCatalogTreeItem &item) {
+ ui::BasicTreeViewItem &child_view_item = build_catalog_items_recursive(*this, item);
+
+ /* Open root-level items by default. */
+ child_view_item.set_collapsed(false);
+ });
+ }
+
+ add_unassigned_item();
+}
+
+ui::BasicTreeViewItem &AssetCatalogTreeView::build_catalog_items_recursive(
+ ui::TreeViewItemContainer &view_parent_item, AssetCatalogTreeItem &catalog)
+{
+ ui::BasicTreeViewItem &view_item = view_parent_item.add_tree_item<AssetCatalogTreeViewItem>(
+ &catalog);
+ if (is_active_catalog(catalog.get_catalog_id())) {
+ view_item.set_active();
+ }
+
+ catalog.foreach_child([&view_item, this](AssetCatalogTreeItem &child) {
+ build_catalog_items_recursive(view_item, child);
+ });
+ return view_item;
+}
+
+void AssetCatalogTreeView::add_all_item()
+{
+ FileAssetSelectParams *params = params_;
+
+ ui::AbstractTreeViewItem &item = add_tree_item<AssetCatalogTreeViewAllItem>(
+ IFACE_("All"), ICON_HOME, [params](ui::BasicTreeViewItem & /*item*/) {
+ params->asset_catalog_visibility = FILE_SHOW_ASSETS_ALL_CATALOGS;
+ WM_main_add_notifier(NC_SPACE | ND_SPACE_ASSET_PARAMS, nullptr);
+ });
+ if (params->asset_catalog_visibility == FILE_SHOW_ASSETS_ALL_CATALOGS) {
+ item.set_active();
+ }
+}
+
+void AssetCatalogTreeView::add_unassigned_item()
+{
+ FileAssetSelectParams *params = params_;
+
+ ui::AbstractTreeViewItem &item = add_tree_item<ui::BasicTreeViewItem>(
+ IFACE_("Unassigned"), ICON_FILE_HIDDEN, [params](ui::BasicTreeViewItem & /*item*/) {
+ params->asset_catalog_visibility = FILE_SHOW_ASSETS_WITHOUT_CATALOG;
+ WM_main_add_notifier(NC_SPACE | ND_SPACE_ASSET_PARAMS, nullptr);
+ });
+ if (params->asset_catalog_visibility == FILE_SHOW_ASSETS_WITHOUT_CATALOG) {
+ item.set_active();
+ }
+}
+
+bool AssetCatalogTreeView::is_active_catalog(CatalogID catalog_id) const
+{
+ return (params_->asset_catalog_visibility == FILE_SHOW_ASSETS_FROM_CATALOG) &&
+ (params_->catalog_id == catalog_id);
+}
+
+} // namespace blender::ed::asset_browser
+
+/* ---------------------------------------------------------------------- */
+
+void file_create_asset_catalog_tree_view_in_layout(::AssetLibrary *asset_library,
+ uiLayout *layout,
+ FileAssetSelectParams *params)
+{
+ uiBlock *block = uiLayoutGetBlock(layout);
+
+ ui::AbstractTreeView *tree_view = UI_block_add_view(
+ *block,
+ "asset catalog tree view",
+ std::make_unique<ed::asset_browser::AssetCatalogTreeView>(asset_library, params));
+
+ ui::TreeViewBuilder builder(*block);
+ builder.build_tree_view(*tree_view);
+}
diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h
index 65e0ad94c72..d39aefff691 100644
--- a/source/blender/editors/space_file/file_intern.h
+++ b/source/blender/editors/space_file/file_intern.h
@@ -31,8 +31,11 @@ extern "C" {
struct ARegion;
struct ARegionType;
+struct AssetLibrary;
struct FileSelectParams;
+struct FileAssetSelectParams;
struct SpaceFile;
+struct uiLayout;
struct View2D;
/* file_draw.c */
@@ -151,12 +154,19 @@ void file_on_reload_callback_register(struct SpaceFile *sfile,
/* file_panels.c */
void file_tool_props_region_panels_register(struct ARegionType *art);
void file_execute_region_panels_register(struct ARegionType *art);
+void file_tools_region_panels_register(struct ARegionType *art);
/* file_utils.c */
void file_tile_boundbox(const ARegion *region, FileLayout *layout, const int file, rcti *r_bounds);
void file_path_to_ui_path(const char *path, char *r_pathi, int max_size);
+/* asset_catalog_tree_view.cc */
+
+void file_create_asset_catalog_tree_view_in_layout(struct AssetLibrary *asset_library,
+ struct uiLayout *layout,
+ struct FileAssetSelectParams *params);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/space_file/file_panels.c b/source/blender/editors/space_file/file_panels.c
index 7032d55b331..95aad202f1a 100644
--- a/source/blender/editors/space_file/file_panels.c
+++ b/source/blender/editors/space_file/file_panels.c
@@ -47,6 +47,7 @@
#include "WM_types.h"
#include "file_intern.h"
+#include "filelist.h"
#include "fsmenu.h"
#include <string.h>
@@ -57,6 +58,12 @@ static bool file_panel_operator_poll(const bContext *C, PanelType *UNUSED(pt))
return (sfile && sfile->op);
}
+static bool file_panel_asset_browsing_poll(const bContext *C, PanelType *UNUSED(pt))
+{
+ SpaceFile *sfile = CTX_wm_space_file(C);
+ return sfile && sfile->files && ED_fileselect_is_asset_browser(sfile);
+}
+
static void file_panel_operator_header(const bContext *C, Panel *panel)
{
SpaceFile *sfile = CTX_wm_space_file(C);
@@ -222,3 +229,28 @@ void file_execute_region_panels_register(ARegionType *art)
pt->draw = file_panel_execution_buttons_draw;
BLI_addtail(&art->paneltypes, pt);
}
+
+static void file_panel_asset_catalog_buttons_draw(const bContext *C, Panel *panel)
+{
+ SpaceFile *sfile = CTX_wm_space_file(C);
+ /* May be null if the library wasn't loaded yet. */
+ struct AssetLibrary *asset_library = filelist_asset_library(sfile->files);
+ FileAssetSelectParams *params = ED_fileselect_get_asset_params(sfile);
+ BLI_assert(params != NULL);
+
+ file_create_asset_catalog_tree_view_in_layout(asset_library, panel->layout, params);
+}
+
+void file_tools_region_panels_register(ARegionType *art)
+{
+ PanelType *pt;
+
+ pt = MEM_callocN(sizeof(PanelType), "spacetype file asset catalog buttons");
+ strcpy(pt->idname, "FILE_PT_asset_catalog_buttons");
+ strcpy(pt->label, N_("Asset Catalogs"));
+ strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
+ pt->flag = PANEL_TYPE_NO_HEADER;
+ pt->poll = file_panel_asset_browsing_poll;
+ pt->draw = file_panel_asset_catalog_buttons_draw;
+ BLI_addtail(&art->paneltypes, pt);
+}
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index 60fe5364aba..91178b85823 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -50,6 +50,7 @@
#include "BLI_task.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
+#include "BLI_uuid.h"
#ifdef WIN32
# include "BLI_winstuff.h"
@@ -369,6 +370,9 @@ typedef struct FileListFilter {
char filter_glob[FILE_MAXFILE];
char filter_search[66]; /* + 2 for heading/trailing implicit '*' wildcards. */
short flags;
+
+ eFileSel_Params_AssetCatalogVisibility asset_catalog_visibility;
+ bUUID asset_catalog_id;
} FileListFilter;
/* FileListFilter.flags */
@@ -806,6 +810,22 @@ static bool is_filtered_hidden(const char *filename,
return true;
}
+ /* TODO Make catalog activation work properly with the "Current File" asset library. Currently
+ * this will only work for external asset data. */
+ if (file->imported_asset_data) {
+ switch (filter->asset_catalog_visibility) {
+ case FILE_SHOW_ASSETS_WITHOUT_CATALOG:
+ return !BLI_uuid_is_nil(file->imported_asset_data->catalog_id);
+ case FILE_SHOW_ASSETS_FROM_CATALOG:
+ /* TODO show all assets that are in child catalogs of the selected catalog. */
+ return BLI_uuid_is_nil(filter->asset_catalog_id) ||
+ !BLI_uuid_equal(filter->asset_catalog_id, file->imported_asset_data->catalog_id);
+ case FILE_SHOW_ASSETS_ALL_CATALOGS:
+ /* All asset files should be visible. */
+ break;
+ }
+ }
+
return false;
}
@@ -1038,6 +1058,33 @@ void filelist_setfilter_options(FileList *filelist,
}
/**
+ * \param catalog_id: The catalog that should be filtered by if \a catalog_visibility is
+ * #FILE_SHOW_ASSETS_FROM_CATALOG. May be NULL otherwise.
+ */
+void filelist_set_asset_catalog_filter_options(
+ FileList *filelist,
+ eFileSel_Params_AssetCatalogVisibility catalog_visibility,
+ const bUUID *catalog_id)
+{
+ bool update = false;
+
+ if (filelist->filter_data.asset_catalog_visibility != catalog_visibility) {
+ filelist->filter_data.asset_catalog_visibility = catalog_visibility;
+ update = true;
+ }
+
+ if (filelist->filter_data.asset_catalog_visibility == FILE_SHOW_ASSETS_FROM_CATALOG &&
+ catalog_id && !BLI_uuid_equal(filelist->filter_data.asset_catalog_id, *catalog_id)) {
+ filelist->filter_data.asset_catalog_id = *catalog_id;
+ update = true;
+ }
+
+ if (update) {
+ filelist_filter_clear(filelist);
+ }
+}
+
+/**
* Checks two libraries for equality.
* \return True if the libraries match.
*/
@@ -1809,6 +1856,11 @@ void filelist_free(struct FileList *filelist)
filelist->flags &= ~(FL_NEED_SORTING | FL_NEED_FILTERING);
}
+AssetLibrary *filelist_asset_library(FileList *filelist)
+{
+ return filelist->asset_library;
+}
+
void filelist_freelib(struct FileList *filelist)
{
if (filelist->libfiledata) {
diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h
index b51ceee4aa0..d1f37b5b365 100644
--- a/source/blender/editors/space_file/filelist.h
+++ b/source/blender/editors/space_file/filelist.h
@@ -31,6 +31,7 @@ struct AssetLibraryReference;
struct BlendHandle;
struct FileList;
struct FileSelection;
+struct bUUID;
struct wmWindowManager;
struct FileDirEntry;
@@ -71,6 +72,10 @@ void filelist_setfilter_options(struct FileList *filelist,
const bool filter_assets_only,
const char *filter_glob,
const char *filter_search);
+void filelist_set_asset_catalog_filter_options(
+ struct FileList *filelist,
+ eFileSel_Params_AssetCatalogVisibility catalog_visibility,
+ const struct bUUID *catalog_id);
void filelist_filter(struct FileList *filelist);
void filelist_setlibrary(struct FileList *filelist,
const struct AssetLibraryReference *asset_library_ref);
@@ -144,6 +149,8 @@ void filelist_entry_parent_select_set(struct FileList *filelist,
void filelist_setrecursion(struct FileList *filelist, const int recursion_level);
+struct AssetLibrary *filelist_asset_library(struct FileList *filelist);
+
struct BlendHandle *filelist_lib(struct FileList *filelist);
bool filelist_islibrary(struct FileList *filelist, char *dir, char **r_group);
void filelist_freelib(struct FileList *filelist);
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index 2ca08a3105c..83b33fe8aa9 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -126,13 +126,10 @@ static void fileselect_ensure_updated_asset_params(SpaceFile *sfile)
FileSelectParams *base_params = &asset_params->base_params;
base_params->file[0] = '\0';
base_params->filter_glob[0] = '\0';
- /* TODO: this way of using filters to form categories is notably slower than specifying a
- * "group" to read. That's because all types are read and filtering is applied afterwards. Would
- * be nice if we could lazy-read individual groups. */
base_params->flag |= U_default.file_space_data.flag | FILE_ASSETS_ONLY | FILE_FILTER;
base_params->flag &= ~FILE_DIRSEL_ONLY;
base_params->filter |= FILE_TYPE_BLENDERLIB;
- base_params->filter_id = FILTER_ID_OB | FILTER_ID_GR;
+ base_params->filter_id = FILTER_ID_ALL;
base_params->display = FILE_IMGDISPLAY;
base_params->sort = FILE_SORT_ALPHA;
/* Asset libraries include all sub-directories, so enable maximal recursion. */
@@ -462,6 +459,15 @@ bool ED_fileselect_is_asset_browser(const SpaceFile *sfile)
return (sfile->browse_mode == FILE_BROWSE_MODE_ASSETS);
}
+struct AssetLibrary *ED_fileselect_active_asset_library_get(const SpaceFile *sfile)
+{
+ if (!ED_fileselect_is_asset_browser(sfile) || !sfile->files) {
+ return NULL;
+ }
+
+ return filelist_asset_library(sfile->files);
+}
+
struct ID *ED_fileselect_active_asset_get(const SpaceFile *sfile)
{
if (!ED_fileselect_is_asset_browser(sfile)) {
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index ac23767f933..a563f24e24e 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -335,9 +335,9 @@ static void file_refresh(const bContext *C, ScrArea *area)
params->highlight_file = -1; /* added this so it opens nicer (ton) */
}
- if (!U.experimental.use_extended_asset_browser && ED_fileselect_is_asset_browser(sfile)) {
+ if (ED_fileselect_is_asset_browser(sfile)) {
/* Only poses supported as non-experimental right now. */
- params->filter_id = FILTER_ID_AC;
+ params->filter_id = U.experimental.use_extended_asset_browser ? FILTER_ID_ALL : FILTER_ID_AC;
}
filelist_settype(sfile->files, params->type);
@@ -355,6 +355,10 @@ static void file_refresh(const bContext *C, ScrArea *area)
(params->flag & FILE_ASSETS_ONLY) != 0,
params->filter_glob,
params->filter_search);
+ if (asset_params) {
+ filelist_set_asset_catalog_filter_options(
+ sfile->files, asset_params->asset_catalog_visibility, &asset_params->catalog_id);
+ }
/* Update the active indices of bookmarks & co. */
sfile->systemnr = fsmenu_get_active_indices(fsmenu, FS_CATEGORY_SYSTEM, params->dir);
@@ -1050,6 +1054,7 @@ void ED_spacetype_file(void)
art->init = file_tools_region_init;
art->draw = file_tools_region_draw;
BLI_addhead(&st->regiontypes, art);
+ file_tools_region_panels_register(art);
/* regions: tool properties */
art = MEM_callocN(sizeof(ARegionType), "spacetype file operator region");
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 2f3f52a6b82..70a1ca63e21 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -806,9 +806,14 @@ typedef struct FileAssetSelectParams {
FileSelectParams base_params;
AssetLibraryReference asset_library_ref;
+ short asset_catalog_visibility; /* eFileSel_Params_AssetCatalogVisibility */
+ char _pad[6];
+ /** If #asset_catalog_visibility is #FILE_SHOW_ASSETS_FROM_CATALOG, this sets the ID of the
+ * catalog to show. */
+ bUUID catalog_id;
short import_type; /* eFileAssetImportType */
- char _pad[6];
+ char _pad2[6];
} FileAssetSelectParams;
typedef enum eFileAssetImportType {
@@ -1009,8 +1014,16 @@ typedef enum eFileSel_Params_Flag {
FILE_HIDE_TOOL_PROPS = (1 << 12),
FILE_CHECK_EXISTING = (1 << 13),
FILE_ASSETS_ONLY = (1 << 14),
+ /** Enables filtering by asset catalog. */
+ FILE_FILTER_ASSET_CATALOG = (1 << 15),
} eFileSel_Params_Flag;
+typedef enum eFileSel_Params_AssetCatalogVisibility {
+ FILE_SHOW_ASSETS_ALL_CATALOGS,
+ FILE_SHOW_ASSETS_FROM_CATALOG,
+ FILE_SHOW_ASSETS_WITHOUT_CATALOG,
+} eFileSel_Params_AssetCatalogVisibility;
+
/* sfile->params->rename_flag */
/* NOTE: short flag. Defined as bitflags, but currently only used as exclusive status markers... */
typedef enum eFileSel_Params_RenameFlag {
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 9e06533d41b..78c26df7be6 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -2614,18 +2614,6 @@ static void rna_FileAssetSelectParams_asset_library_set(PointerRNA *ptr, int val
params->asset_library_ref = ED_asset_library_reference_from_enum_value(value);
}
-static void rna_FileAssetSelectParams_asset_category_set(PointerRNA *ptr, uint64_t value)
-{
- FileSelectParams *params = ptr->data;
- params->filter_id = value;
-}
-
-static uint64_t rna_FileAssetSelectParams_asset_category_get(PointerRNA *ptr)
-{
- FileSelectParams *params = ptr->data;
- return params->filter_id;
-}
-
static PointerRNA rna_FileBrowser_FileSelectEntry_asset_data_get(PointerRNA *ptr)
{
const FileDirEntry *entry = ptr->data;
@@ -6595,47 +6583,6 @@ static void rna_def_fileselect_asset_params(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
- /* XXX copied from rna_enum_id_type_filter_items. */
- static const EnumPropertyItem asset_category_items[] = {
- {FILTER_ID_SCE, "SCENES", ICON_SCENE_DATA, "Scenes", "Show scenes"},
- {FILTER_ID_AC, "ANIMATIONS", ICON_ANIM_DATA, "Animations", "Show animation data"},
- {FILTER_ID_OB | FILTER_ID_GR,
- "OBJECTS_AND_COLLECTIONS",
- ICON_GROUP,
- "Objects & Collections",
- "Show objects and collections"},
- {FILTER_ID_AR | FILTER_ID_CU | FILTER_ID_LT | FILTER_ID_MB | FILTER_ID_ME
- /* XXX avoid warning */
- // | FILTER_ID_HA | FILTER_ID_PT | FILTER_ID_VO
- ,
- "GEOMETRY",
- ICON_MESH_DATA,
- "Geometry",
- "Show meshes, curves, lattice, armatures and metaballs data"},
- {FILTER_ID_LS | FILTER_ID_MA | FILTER_ID_NT | FILTER_ID_TE,
- "SHADING",
- ICON_MATERIAL_DATA,
- "Shading",
- "Show materials, nodetrees, textures and Freestyle's linestyles"},
- {FILTER_ID_IM | FILTER_ID_MC | FILTER_ID_MSK | FILTER_ID_SO,
- "IMAGES_AND_SOUNDS",
- ICON_IMAGE_DATA,
- "Images & Sounds",
- "Show images, movie clips, sounds and masks"},
- {FILTER_ID_CA | FILTER_ID_LA | FILTER_ID_LP | FILTER_ID_SPK | FILTER_ID_WO,
- "ENVIRONMENTS",
- ICON_WORLD_DATA,
- "Environment",
- "Show worlds, lights, cameras and speakers"},
- {FILTER_ID_BR | FILTER_ID_GD | FILTER_ID_PA | FILTER_ID_PAL | FILTER_ID_PC | FILTER_ID_TXT |
- FILTER_ID_VF | FILTER_ID_CF | FILTER_ID_WS,
- "MISC",
- ICON_GREASEPENCIL,
- "Miscellaneous",
- "Show other data types"},
- {0, NULL, 0, NULL, NULL},
- };
-
static const EnumPropertyItem asset_import_type_items[] = {
{FILE_ASSET_IMPORT_LINK, "LINK", 0, "Link", "Import the assets as linked data-block"},
{FILE_ASSET_IMPORT_APPEND,
@@ -6664,15 +6611,6 @@ static void rna_def_fileselect_asset_params(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Asset Library", "");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
- prop = RNA_def_property(srna, "asset_category", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, asset_category_items);
- RNA_def_property_enum_funcs(prop,
- "rna_FileAssetSelectParams_asset_category_get",
- "rna_FileAssetSelectParams_asset_category_set",
- NULL);
- RNA_def_property_ui_text(prop, "Asset Category", "Determine which kind of assets to display");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
-
prop = RNA_def_property(srna, "import_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, asset_import_type_items);
RNA_def_property_ui_text(prop, "Import Type", "Determine how the asset will be imported");