Geometry Nodes: Show uncategorized assets in separate menus

In the add modifier menu, 3D viewport menus for node tools, and the node
editor add menu, assets not in catalogs are added to an "No Catalog"
menu rather than not being accessible at all.

This makes the default behavior when adding a node tool "not broken"
so at least something happens by default. The question of "How do I
add a catalog?" is much better than "Why didn't anything happen?"

Implements #111529
See #101778

---

![image](/attachments/b943e2c4-f660-4812-b9ab-f7c116b68b98)
![image](/attachments/e6ee94d7-cd14-475f-8fa6-abcc6774fd7e)
![image](/attachments/b1718d0c-4182-49c5-867a-1399082e98f0)

Pull Request: https://projects.blender.org/blender/blender/pulls/112355
This commit is contained in:
Hans Goudey 2023-09-14 17:35:24 +02:00 committed by Hans Goudey
parent 4aa3735d0f
commit d2d4de8c71
9 changed files with 143 additions and 6 deletions

View File

@ -12,6 +12,7 @@
#include "BLI_function_ref.hh"
#include "BLI_multi_value_map.hh"
#include "BLI_vector.hh"
#include "AS_asset_catalog_path.hh"
#include "AS_asset_catalog_tree.hh"
@ -47,6 +48,8 @@ struct AssetItemTree {
asset_system::AssetCatalogTree catalogs;
MultiValueMap<asset_system::AssetCatalogPath, asset_system::AssetRepresentation *>
assets_per_path;
/** Assets not added to a catalog, not part of #assets_per_path. */
Vector<asset_system::AssetRepresentation *> unassigned_assets;
};
asset_system::AssetCatalogTree build_filtered_catalog_tree(

View File

@ -107,6 +107,7 @@ AssetItemTree build_filtered_all_catalog_tree(
{
MultiValueMap<asset_system::AssetCatalogPath, asset_system::AssetRepresentation *>
assets_per_path;
Vector<asset_system::AssetRepresentation *> unassigned_assets;
ED_assetlist_storage_fetch(&library_ref, &C);
ED_assetlist_ensure_previews_job(&library_ref, &C);
@ -120,17 +121,21 @@ AssetItemTree build_filtered_all_catalog_tree(
return true;
}
const AssetMetaData &meta_data = asset.get_metadata();
if (BLI_uuid_is_nil(meta_data.catalog_id)) {
if (meta_data_filter && !meta_data_filter(meta_data)) {
return true;
}
if (meta_data_filter && !meta_data_filter(meta_data)) {
if (BLI_uuid_is_nil(meta_data.catalog_id)) {
unassigned_assets.append(&asset);
return true;
}
const asset_system::AssetCatalog *catalog = library->catalog_service->find_catalog(
meta_data.catalog_id);
if (catalog == nullptr) {
/* Also include assets with catalogs we're unable to find (e.g. the catalog was deleted) in
* the "Unassigned" list. */
unassigned_assets.append(&asset);
return true;
}
assets_per_path.add(catalog->path, &asset);
@ -151,7 +156,9 @@ AssetItemTree build_filtered_all_catalog_tree(
catalogs_with_node_assets.insert_item(*catalog);
});
return {std::move(catalogs_with_node_assets), std::move(assets_per_path)};
return {std::move(catalogs_with_node_assets),
std::move(assets_per_path),
std::move(unassigned_assets)};
}
} // namespace blender::ed::asset

View File

@ -672,6 +672,41 @@ MenuType node_group_operator_assets_menu()
return type;
}
static void catalog_assets_draw_unassigned(const bContext *C, Menu *menu)
{
asset::AssetItemTree *tree = get_static_item_tree(*C);
if (!tree) {
return;
}
for (const asset_system::AssetRepresentation *asset : tree->unassigned_assets) {
wmOperatorType *ot = WM_operatortype_find("GEOMETRY_OT_execute_node_group", true);
PointerRNA props_ptr;
uiItemFullO_ptr(menu->layout,
ot,
IFACE_(asset->get_name().c_str()),
ICON_NONE,
nullptr,
WM_OP_INVOKE_DEFAULT,
UI_ITEM_NONE,
&props_ptr);
asset::operator_asset_reference_props_set(*asset, props_ptr);
}
}
MenuType node_group_operator_assets_menu_unassigned()
{
MenuType type{};
STRNCPY(type.idname, "GEO_MT_node_operator_catalog_assets_unassigned");
type.poll = asset_menu_poll;
type.draw = catalog_assets_draw_unassigned;
type.listener = asset::asset_reading_region_listen_fn;
type.flag = MenuTypeFlag::ContextDependent;
type.description = N_(
"Tool node group assets not assigned to a catalog.\n"
"Catalogs can be assigned in the Asset Browser.");
return type;
}
void ui_template_node_operator_asset_menu_items(uiLayout &layout,
bContext &C,
const StringRef catalog_path)
@ -712,9 +747,6 @@ void ui_template_node_operator_asset_root_items(uiLayout &layout, bContext &C)
return;
}
*tree = build_catalog_tree(C);
if (tree->catalogs.is_empty()) {
return;
}
asset_system::AssetLibrary *all_library = ED_assetlist_library_get_once_available(
asset_system::all_library_reference());
@ -731,6 +763,13 @@ void ui_template_node_operator_asset_root_items(uiLayout &layout, bContext &C)
screen, *all_library, item, "GEO_MT_node_operator_catalog_assets", layout);
}
});
if (!tree->unassigned_assets.is_empty()) {
uiItemM(&layout,
"GEO_MT_node_operator_catalog_assets_unassigned",
IFACE_("No Catalog"),
ICON_NONE);
}
}
/** \} */

View File

@ -35,6 +35,7 @@ bool ED_geometry_attribute_convert(Mesh *mesh,
namespace blender::ed::geometry {
MenuType node_group_operator_assets_menu();
MenuType node_group_operator_assets_menu_unassigned();
void ui_template_node_operator_asset_menu_items(uiLayout &layout,
bContext &C,

View File

@ -122,6 +122,24 @@ static void catalog_assets_draw(const bContext *C, Menu *menu)
});
}
static void unassigned_assets_draw(const bContext * /*C*/, Menu *menu)
{
asset::AssetItemTree &tree = *get_static_item_tree();
for (const asset_system::AssetRepresentation *asset : tree.unassigned_assets) {
wmOperatorType *ot = WM_operatortype_find("OBJECT_OT_modifier_add_asset", true);
PointerRNA props_ptr;
uiItemFullO_ptr(menu->layout,
ot,
IFACE_(asset->get_name().c_str()),
ICON_NONE,
nullptr,
WM_OP_INVOKE_DEFAULT,
UI_ITEM_NONE,
&props_ptr);
asset::operator_asset_reference_props_set(*asset, props_ptr);
}
}
static void root_catalogs_draw(const bContext *C, Menu *menu)
{
const Object *object = ED_object_active_context(C);
@ -174,6 +192,11 @@ static void root_catalogs_draw(const bContext *C, Menu *menu)
screen, *all_library, item, "OBJECT_MT_add_modifier_catalog_assets", *layout);
}
});
if (!tree.unassigned_assets.is_empty()) {
uiItemS(layout);
uiItemM(layout, "OBJECT_MT_add_modifier_unassigned_assets", IFACE_("No Catalog"), ICON_NONE);
}
}
static bNodeTree *get_node_group(const bContext &C, PointerRNA &ptr, ReportList *reports)
@ -259,6 +282,19 @@ static void OBJECT_OT_modifier_add_asset(wmOperatorType *ot)
asset::operator_asset_reference_props_register(*ot->srna);
}
static MenuType modifier_add_unassigned_assets_menu_type()
{
MenuType type{};
STRNCPY(type.idname, "OBJECT_MT_add_modifier_unassigned_assets");
type.draw = unassigned_assets_draw;
type.listener = asset::asset_reading_region_listen_fn;
type.flag = MenuTypeFlag::ContextDependent;
type.description = N_(
"Modifier node group assets not assigned to a catalog.\n"
"Catalogs can be assigned in the Asset Browser.");
return type;
}
static MenuType modifier_add_catalog_assets_menu_type()
{
MenuType type{};
@ -282,6 +318,7 @@ static MenuType modifier_add_root_catalogs_menu_type()
void object_modifier_add_asset_register()
{
WM_menutype_add(MEM_new<MenuType>(__func__, modifier_add_catalog_assets_menu_type()));
WM_menutype_add(MEM_new<MenuType>(__func__, modifier_add_unassigned_assets_menu_type()));
WM_menutype_add(MEM_new<MenuType>(__func__, modifier_add_root_catalogs_menu_type()));
WM_operatortype_append(OBJECT_OT_modifier_add_asset);
}

View File

@ -113,6 +113,33 @@ static void node_add_catalog_assets_draw(const bContext *C, Menu *menu)
});
}
static void node_add_unassigned_assets_draw(const bContext *C, Menu *menu)
{
SpaceNode &snode = *CTX_wm_space_node(C);
const bNodeTree *edit_tree = snode.edittree;
if (!edit_tree) {
return;
}
if (!snode.runtime->assets_for_menu) {
snode.runtime->assets_for_menu = std::make_shared<asset::AssetItemTree>(
build_catalog_tree(*C, *edit_tree));
return;
}
asset::AssetItemTree &tree = *snode.runtime->assets_for_menu;
for (const asset_system::AssetRepresentation *asset : tree.unassigned_assets) {
PointerRNA op_ptr;
uiItemFullO(menu->layout,
"NODE_OT_add_group_asset",
IFACE_(asset->get_name().c_str()),
ICON_NONE,
nullptr,
WM_OP_INVOKE_DEFAULT,
UI_ITEM_NONE,
&op_ptr);
asset::operator_asset_reference_props_set(*asset, op_ptr);
}
}
static void add_root_catalogs_draw(const bContext *C, Menu *menu)
{
bScreen &screen = *CTX_wm_screen(C);
@ -186,6 +213,11 @@ static void add_root_catalogs_draw(const bContext *C, Menu *menu)
screen, *all_library, item, "NODE_MT_node_add_catalog_assets", *layout);
}
});
if (!tree.unassigned_assets.is_empty()) {
uiItemS(layout);
uiItemM(layout, "NODE_MT_node_add_unassigned_assets", IFACE_("No Catalog"), ICON_NONE);
}
}
MenuType add_catalog_assets_menu_type()
@ -199,6 +231,20 @@ MenuType add_catalog_assets_menu_type()
return type;
}
MenuType add_unassigned_assets_menu_type()
{
MenuType type{};
STRNCPY(type.idname, "NODE_MT_node_add_unassigned_assets");
type.poll = node_add_menu_poll;
type.draw = node_add_unassigned_assets_draw;
type.listener = asset::asset_reading_region_listen_fn;
type.flag = MenuTypeFlag::ContextDependent;
type.description = N_(
"Node group assets not assigned to a catalog.\n"
"Catalogs can be assigned in the Asset Browser.");
return type;
}
MenuType add_root_catalogs_menu_type()
{
MenuType type{};

View File

@ -405,6 +405,7 @@ void invoke_node_link_drag_add_menu(bContext &C,
/* `add_menu_assets.cc` */
MenuType add_catalog_assets_menu_type();
MenuType add_unassigned_assets_menu_type();
MenuType add_root_catalogs_menu_type();
} // namespace blender::ed::space_node

View File

@ -1311,6 +1311,7 @@ void ED_spacetype_node()
BLI_addhead(&st->regiontypes, art);
WM_menutype_add(MEM_new<MenuType>(__func__, add_catalog_assets_menu_type()));
WM_menutype_add(MEM_new<MenuType>(__func__, add_unassigned_assets_menu_type()));
WM_menutype_add(MEM_new<MenuType>(__func__, add_root_catalogs_menu_type()));
BKE_spacetype_register(st);

View File

@ -2293,6 +2293,8 @@ void ED_spacetype_view3d()
WM_menutype_add(
MEM_new<MenuType>(__func__, blender::ed::geometry::node_group_operator_assets_menu()));
WM_menutype_add(MEM_new<MenuType>(
__func__, blender::ed::geometry::node_group_operator_assets_menu_unassigned()));
BKE_spacetype_register(st);
}