Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/space_node/add_menu_assets.cc
| /* SPDX-License-Identifier: GPL-2.0-or-later */ | /* SPDX-License-Identifier: GPL-2.0-or-later */ | ||||
| #include "AS_asset_catalog.hh" | |||||
| #include "AS_asset_library.hh" | |||||
| #include "BLI_multi_value_map.hh" | #include "BLI_multi_value_map.hh" | ||||
| #include "DNA_screen_types.h" | #include "DNA_screen_types.h" | ||||
| #include "DNA_space_types.h" | #include "DNA_space_types.h" | ||||
| #include "BKE_asset.h" | #include "BKE_asset.h" | ||||
| #include "BKE_asset_catalog.hh" | |||||
| #include "BKE_asset_library.hh" | |||||
| #include "BKE_idprop.h" | #include "BKE_idprop.h" | ||||
| #include "BKE_screen.h" | #include "BKE_screen.h" | ||||
| #include "BLT_translation.h" | #include "BLT_translation.h" | ||||
| #include "RNA_access.h" | #include "RNA_access.h" | ||||
| #include "RNA_prototypes.h" | #include "RNA_prototypes.h" | ||||
| Show All 24 Lines | |||||
| } | } | ||||
| struct LibraryAsset { | struct LibraryAsset { | ||||
| AssetLibraryReference library_ref; | AssetLibraryReference library_ref; | ||||
| AssetHandle handle; | AssetHandle handle; | ||||
| }; | }; | ||||
| struct LibraryCatalog { | struct LibraryCatalog { | ||||
| bke::AssetLibrary *library; | asset_system::AssetLibrary *library; | ||||
| const bke::AssetCatalog *catalog; | const asset_system::AssetCatalog *catalog; | ||||
| }; | }; | ||||
| struct AssetItemTree { | struct AssetItemTree { | ||||
| bke::AssetCatalogTree catalogs; | asset_system::AssetCatalogTree catalogs; | ||||
| MultiValueMap<bke::AssetCatalogPath, LibraryAsset> assets_per_path; | MultiValueMap<asset_system::AssetCatalogPath, LibraryAsset> assets_per_path; | ||||
| Map<const bke::AssetCatalogTreeItem *, bke::AssetCatalogPath> full_catalog_per_tree_item; | Map<const asset_system::AssetCatalogTreeItem *, asset_system::AssetCatalogPath> | ||||
| full_catalog_per_tree_item; | |||||
| }; | }; | ||||
| static bool all_loading_finished() | static bool all_loading_finished() | ||||
| { | { | ||||
| for (const AssetLibraryReference &library : bke::all_valid_asset_library_refs()) { | for (const AssetLibraryReference &library : asset_system::all_valid_asset_library_refs()) { | ||||
| if (!ED_assetlist_is_loaded(&library)) { | if (!ED_assetlist_is_loaded(&library)) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| } | } | ||||
| return true; | return true; | ||||
| } | } | ||||
| static AssetItemTree build_catalog_tree(const bContext &C, const bNodeTree *node_tree) | static AssetItemTree build_catalog_tree(const bContext &C, const bNodeTree *node_tree) | ||||
| { | { | ||||
| if (!node_tree) { | if (!node_tree) { | ||||
| return {}; | return {}; | ||||
| } | } | ||||
| const Main &bmain = *CTX_data_main(&C); | const Main &bmain = *CTX_data_main(&C); | ||||
| const Vector<AssetLibraryReference> all_libraries = bke::all_valid_asset_library_refs(); | const Vector<AssetLibraryReference> all_libraries = asset_system::all_valid_asset_library_refs(); | ||||
| /* Merge catalogs from all libraries to deduplicate menu items. Also store the catalog and | /* Merge catalogs from all libraries to deduplicate menu items. Also store the catalog and | ||||
| * library for each asset ID in order to use them later when retrieving assets and removing | * library for each asset ID in order to use them later when retrieving assets and removing | ||||
| * empty catalogs. */ | * empty catalogs. */ | ||||
| Map<bke::CatalogID, LibraryCatalog> id_to_catalog_map; | Map<asset_system::CatalogID, LibraryCatalog> id_to_catalog_map; | ||||
| bke::AssetCatalogTree catalogs_from_all_libraries; | asset_system::AssetCatalogTree catalogs_from_all_libraries; | ||||
| for (const AssetLibraryReference &library_ref : all_libraries) { | for (const AssetLibraryReference &library_ref : all_libraries) { | ||||
| if (bke::AssetLibrary *library = BKE_asset_library_load(&bmain, library_ref)) { | if (asset_system::AssetLibrary *library = AS_asset_library_load(&bmain, library_ref)) { | ||||
| if (bke::AssetCatalogTree *tree = library->catalog_service->get_catalog_tree()) { | if (asset_system::AssetCatalogTree *tree = library->catalog_service->get_catalog_tree()) { | ||||
| tree->foreach_item([&](bke::AssetCatalogTreeItem &item) { | tree->foreach_item([&](asset_system::AssetCatalogTreeItem &item) { | ||||
| const bke::CatalogID &id = item.get_catalog_id(); | const asset_system::CatalogID &id = item.get_catalog_id(); | ||||
| bke::AssetCatalog *catalog = library->catalog_service->find_catalog(id); | asset_system::AssetCatalog *catalog = library->catalog_service->find_catalog(id); | ||||
| catalogs_from_all_libraries.insert_item(*catalog); | catalogs_from_all_libraries.insert_item(*catalog); | ||||
| id_to_catalog_map.add(item.get_catalog_id(), LibraryCatalog{library, catalog}); | id_to_catalog_map.add(item.get_catalog_id(), LibraryCatalog{library, catalog}); | ||||
| }); | }); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* Find all the matching node group assets for every catalog path. */ | /* Find all the matching node group assets for every catalog path. */ | ||||
| MultiValueMap<bke::AssetCatalogPath, LibraryAsset> assets_per_path; | MultiValueMap<asset_system::AssetCatalogPath, LibraryAsset> assets_per_path; | ||||
| for (const AssetLibraryReference &library_ref : all_libraries) { | for (const AssetLibraryReference &library_ref : all_libraries) { | ||||
| AssetFilterSettings type_filter{}; | AssetFilterSettings type_filter{}; | ||||
| type_filter.id_types = FILTER_ID_NT; | type_filter.id_types = FILTER_ID_NT; | ||||
| ED_assetlist_storage_fetch(&library_ref, &C); | ED_assetlist_storage_fetch(&library_ref, &C); | ||||
| ED_assetlist_ensure_previews_job(&library_ref, &C); | ED_assetlist_ensure_previews_job(&library_ref, &C); | ||||
| ED_assetlist_iterate(library_ref, [&](AssetHandle asset) { | ED_assetlist_iterate(library_ref, [&](AssetHandle asset) { | ||||
| if (!ED_asset_filter_matches_asset(&type_filter, &asset)) { | if (!ED_asset_filter_matches_asset(&type_filter, &asset)) { | ||||
| Show All 12 Lines | ED_assetlist_iterate(library_ref, [&](AssetHandle asset) { | ||||
| return true; | return true; | ||||
| } | } | ||||
| assets_per_path.add(library_catalog->catalog->path, LibraryAsset{library_ref, asset}); | assets_per_path.add(library_catalog->catalog->path, LibraryAsset{library_ref, asset}); | ||||
| return true; | return true; | ||||
| }); | }); | ||||
| } | } | ||||
| /* Build the final tree without any of the catalogs that don't have proper node group assets. */ | /* Build the final tree without any of the catalogs that don't have proper node group assets. */ | ||||
| bke::AssetCatalogTree catalogs_with_node_assets; | asset_system::AssetCatalogTree catalogs_with_node_assets; | ||||
| catalogs_from_all_libraries.foreach_item([&](bke::AssetCatalogTreeItem &item) { | catalogs_from_all_libraries.foreach_item([&](asset_system::AssetCatalogTreeItem &item) { | ||||
| if (!assets_per_path.lookup(item.catalog_path()).is_empty()) { | if (!assets_per_path.lookup(item.catalog_path()).is_empty()) { | ||||
| const bke::CatalogID &id = item.get_catalog_id(); | const asset_system::CatalogID &id = item.get_catalog_id(); | ||||
| const LibraryCatalog &library_catalog = id_to_catalog_map.lookup(id); | const LibraryCatalog &library_catalog = id_to_catalog_map.lookup(id); | ||||
| bke::AssetCatalog *catalog = library_catalog.library->catalog_service->find_catalog(id); | asset_system::AssetCatalog *catalog = library_catalog.library->catalog_service->find_catalog( | ||||
| id); | |||||
| catalogs_with_node_assets.insert_item(*catalog); | catalogs_with_node_assets.insert_item(*catalog); | ||||
| } | } | ||||
| }); | }); | ||||
| /* Build another map storing full asset paths for each tree item, in order to have stable | /* Build another map storing full asset paths for each tree item, in order to have stable | ||||
| * pointers to asset catalog paths to use for context pointers. This is necessary because | * pointers to asset catalog paths to use for context pointers. This is necessary because | ||||
| * #bke::AssetCatalogTreeItem doesn't store its full path directly. */ | * #asset_system::AssetCatalogTreeItem doesn't store its full path directly. */ | ||||
| Map<const bke::AssetCatalogTreeItem *, bke::AssetCatalogPath> full_catalog_per_tree_item; | Map<const asset_system::AssetCatalogTreeItem *, asset_system::AssetCatalogPath> | ||||
| catalogs_with_node_assets.foreach_item([&](bke::AssetCatalogTreeItem &item) { | full_catalog_per_tree_item; | ||||
| catalogs_with_node_assets.foreach_item([&](asset_system::AssetCatalogTreeItem &item) { | |||||
| full_catalog_per_tree_item.add_new(&item, item.catalog_path()); | full_catalog_per_tree_item.add_new(&item, item.catalog_path()); | ||||
| }); | }); | ||||
| return {std::move(catalogs_with_node_assets), | return {std::move(catalogs_with_node_assets), | ||||
| std::move(assets_per_path), | std::move(assets_per_path), | ||||
| std::move(full_catalog_per_tree_item)}; | std::move(full_catalog_per_tree_item)}; | ||||
| } | } | ||||
| Show All 10 Lines | static void node_add_catalog_assets_draw(const bContext *C, Menu *menu) | ||||
| if (!edit_tree) { | if (!edit_tree) { | ||||
| return; | return; | ||||
| } | } | ||||
| const PointerRNA menu_path_ptr = CTX_data_pointer_get(C, "asset_catalog_path"); | const PointerRNA menu_path_ptr = CTX_data_pointer_get(C, "asset_catalog_path"); | ||||
| if (RNA_pointer_is_null(&menu_path_ptr)) { | if (RNA_pointer_is_null(&menu_path_ptr)) { | ||||
| return; | return; | ||||
| } | } | ||||
| const bke::AssetCatalogPath &menu_path = *static_cast<const bke::AssetCatalogPath *>( | const asset_system::AssetCatalogPath &menu_path = | ||||
| menu_path_ptr.data); | *static_cast<const asset_system::AssetCatalogPath *>(menu_path_ptr.data); | ||||
| const Span<LibraryAsset> asset_items = tree.assets_per_path.lookup(menu_path); | const Span<LibraryAsset> asset_items = tree.assets_per_path.lookup(menu_path); | ||||
| bke::AssetCatalogTreeItem *catalog_item = tree.catalogs.find_item(menu_path); | asset_system::AssetCatalogTreeItem *catalog_item = tree.catalogs.find_item(menu_path); | ||||
| BLI_assert(catalog_item != nullptr); | BLI_assert(catalog_item != nullptr); | ||||
| if (asset_items.is_empty() && !catalog_item->has_children()) { | if (asset_items.is_empty() && !catalog_item->has_children()) { | ||||
| return; | return; | ||||
| } | } | ||||
| uiLayout *layout = menu->layout; | uiLayout *layout = menu->layout; | ||||
| uiItemS(layout); | uiItemS(layout); | ||||
| for (const LibraryAsset &item : asset_items) { | for (const LibraryAsset &item : asset_items) { | ||||
| uiLayout *col = uiLayoutColumn(layout, false); | uiLayout *col = uiLayoutColumn(layout, false); | ||||
| PointerRNA file{ | PointerRNA file{ | ||||
| &screen.id, &RNA_FileSelectEntry, const_cast<FileDirEntry *>(item.handle.file_data)}; | &screen.id, &RNA_FileSelectEntry, const_cast<FileDirEntry *>(item.handle.file_data)}; | ||||
| uiLayoutSetContextPointer(col, "active_file", &file); | uiLayoutSetContextPointer(col, "active_file", &file); | ||||
| PointerRNA library_ptr{&screen.id, | PointerRNA library_ptr{&screen.id, | ||||
| &RNA_AssetLibraryReference, | &RNA_AssetLibraryReference, | ||||
| const_cast<AssetLibraryReference *>(&item.library_ref)}; | const_cast<AssetLibraryReference *>(&item.library_ref)}; | ||||
| uiLayoutSetContextPointer(col, "asset_library_ref", &library_ptr); | uiLayoutSetContextPointer(col, "asset_library_ref", &library_ptr); | ||||
| uiItemO(col, ED_asset_handle_get_name(&item.handle), ICON_NONE, "NODE_OT_add_group_asset"); | uiItemO(col, ED_asset_handle_get_name(&item.handle), ICON_NONE, "NODE_OT_add_group_asset"); | ||||
| } | } | ||||
| catalog_item->foreach_child([&](bke::AssetCatalogTreeItem &child_item) { | catalog_item->foreach_child([&](asset_system::AssetCatalogTreeItem &child_item) { | ||||
| const bke::AssetCatalogPath &path = tree.full_catalog_per_tree_item.lookup(&child_item); | const asset_system::AssetCatalogPath &path = tree.full_catalog_per_tree_item.lookup( | ||||
| &child_item); | |||||
| PointerRNA path_ptr{ | PointerRNA path_ptr{ | ||||
| &screen.id, &RNA_AssetCatalogPath, const_cast<bke::AssetCatalogPath *>(&path)}; | &screen.id, &RNA_AssetCatalogPath, const_cast<asset_system::AssetCatalogPath *>(&path)}; | ||||
| uiLayout *col = uiLayoutColumn(layout, false); | uiLayout *col = uiLayoutColumn(layout, false); | ||||
| uiLayoutSetContextPointer(col, "asset_catalog_path", &path_ptr); | uiLayoutSetContextPointer(col, "asset_catalog_path", &path_ptr); | ||||
| uiItemM(col, "NODE_MT_node_add_catalog_assets", path.name().c_str(), ICON_NONE); | uiItemM(col, "NODE_MT_node_add_catalog_assets", path.name().c_str(), ICON_NONE); | ||||
| }); | }); | ||||
| } | } | ||||
| static void add_root_catalogs_draw(const bContext *C, Menu *menu) | static void add_root_catalogs_draw(const bContext *C, Menu *menu) | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | static Set<std::string> all_builtin_menus = []() { | ||||
| menus.add_new("UV"); | menus.add_new("UV"); | ||||
| menus.add_new("Vector"); | menus.add_new("Vector"); | ||||
| menus.add_new("Volume"); | menus.add_new("Volume"); | ||||
| menus.add_new("Group"); | menus.add_new("Group"); | ||||
| menus.add_new("Layout"); | menus.add_new("Layout"); | ||||
| return menus; | return menus; | ||||
| }(); | }(); | ||||
| tree.catalogs.foreach_root_item([&](bke::AssetCatalogTreeItem &item) { | tree.catalogs.foreach_root_item([&](asset_system::AssetCatalogTreeItem &item) { | ||||
| if (all_builtin_menus.contains(item.get_name())) { | if (all_builtin_menus.contains(item.get_name())) { | ||||
| return; | return; | ||||
| } | } | ||||
| const bke::AssetCatalogPath &path = tree.full_catalog_per_tree_item.lookup(&item); | const asset_system::AssetCatalogPath &path = tree.full_catalog_per_tree_item.lookup(&item); | ||||
| PointerRNA path_ptr{ | PointerRNA path_ptr{ | ||||
| &screen.id, &RNA_AssetCatalogPath, const_cast<bke::AssetCatalogPath *>(&path)}; | &screen.id, &RNA_AssetCatalogPath, const_cast<asset_system::AssetCatalogPath *>(&path)}; | ||||
| uiLayout *col = uiLayoutColumn(layout, false); | uiLayout *col = uiLayoutColumn(layout, false); | ||||
| uiLayoutSetContextPointer(col, "asset_catalog_path", &path_ptr); | uiLayoutSetContextPointer(col, "asset_catalog_path", &path_ptr); | ||||
| uiItemM(col, "NODE_MT_node_add_catalog_assets", path.name().c_str(), ICON_NONE); | uiItemM(col, "NODE_MT_node_add_catalog_assets", path.name().c_str(), ICON_NONE); | ||||
| }); | }); | ||||
| } | } | ||||
| MenuType add_catalog_assets_menu_type() | MenuType add_catalog_assets_menu_type() | ||||
| { | { | ||||
| Show All 20 Lines | |||||
| /* Note: This is only necessary because Python can't set an asset catalog path context item. */ | /* Note: This is only necessary because Python can't set an asset catalog path context item. */ | ||||
| void uiTemplateNodeAssetMenuItems(uiLayout *layout, bContext *C, const char *catalog_path) | void uiTemplateNodeAssetMenuItems(uiLayout *layout, bContext *C, const char *catalog_path) | ||||
| { | { | ||||
| using namespace blender; | using namespace blender; | ||||
| using namespace blender::ed::space_node; | using namespace blender::ed::space_node; | ||||
| bScreen &screen = *CTX_wm_screen(C); | bScreen &screen = *CTX_wm_screen(C); | ||||
| SpaceNode &snode = *CTX_wm_space_node(C); | SpaceNode &snode = *CTX_wm_space_node(C); | ||||
| AssetItemTree &tree = *snode.runtime->assets_for_menu; | AssetItemTree &tree = *snode.runtime->assets_for_menu; | ||||
| const bke::AssetCatalogTreeItem *item = tree.catalogs.find_root_item(catalog_path); | const asset_system::AssetCatalogTreeItem *item = tree.catalogs.find_root_item(catalog_path); | ||||
| if (!item) { | if (!item) { | ||||
| return; | return; | ||||
| } | } | ||||
| const bke::AssetCatalogPath &path = tree.full_catalog_per_tree_item.lookup(item); | const asset_system::AssetCatalogPath &path = tree.full_catalog_per_tree_item.lookup(item); | ||||
| PointerRNA path_ptr{ | PointerRNA path_ptr{ | ||||
| &screen.id, &RNA_AssetCatalogPath, const_cast<bke::AssetCatalogPath *>(&path)}; | &screen.id, &RNA_AssetCatalogPath, const_cast<asset_system::AssetCatalogPath *>(&path)}; | ||||
| uiItemS(layout); | uiItemS(layout); | ||||
| uiLayout *col = uiLayoutColumn(layout, false); | uiLayout *col = uiLayoutColumn(layout, false); | ||||
| uiLayoutSetContextPointer(col, "asset_catalog_path", &path_ptr); | uiLayoutSetContextPointer(col, "asset_catalog_path", &path_ptr); | ||||
| uiItemMContents(col, "NODE_MT_node_add_catalog_assets"); | uiItemMContents(col, "NODE_MT_node_add_catalog_assets"); | ||||
| } | } | ||||