Blender V4.5
add_modifier_assets.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "AS_asset_catalog.hh"
7#include "AS_asset_library.hh"
9
10#include "BLI_listbase.h"
12#include "BLI_string.h"
13
14#include "DNA_modifier_types.h"
15#include "DNA_screen_types.h"
16#include "DNA_space_types.h"
17
18#include "BKE_asset.hh"
19#include "BKE_context.hh"
20#include "BKE_idprop.hh"
21#include "BKE_lib_id.hh"
22#include "BKE_main.hh"
23#include "BKE_modifier.hh"
24#include "BKE_report.hh"
25#include "BKE_screen.hh"
26
27#include "BLT_translation.hh"
28
29#include "RNA_access.hh"
30
31#include "ED_asset.hh"
33#include "ED_object.hh"
34#include "ED_screen.hh"
35
36#include "MOD_nodes.hh"
37
38#include "UI_interface.hh"
39
40#include "WM_api.hh"
41
42#include "object_intern.hh"
43
44namespace blender::ed::object {
45
47{
49 return asset::list::is_loaded(&all_library_ref);
50}
51
53{
54 asset::AssetFilterSettings type_filter{};
55 type_filter.id_types = FILTER_ID_NT;
56 auto meta_data_filter = [&](const AssetMetaData &meta_data) {
57 const IDProperty *tree_type = BKE_asset_metadata_idprop_find(&meta_data, "type");
58 if (tree_type == nullptr || IDP_Int(tree_type) != NTREE_GEOMETRY) {
59 return false;
60 }
61 const IDProperty *traits_flag = BKE_asset_metadata_idprop_find(
62 &meta_data, "geometry_node_asset_traits_flag");
63 if (traits_flag == nullptr || !(IDP_Int(traits_flag) & GEO_NODE_ASSET_MODIFIER)) {
64 return false;
65 }
66 return true;
67 };
70 return asset::build_filtered_all_catalog_tree(library, C, type_filter, meta_data_filter);
71}
72
78
79static void catalog_assets_draw(const bContext *C, Menu *menu)
80{
82
83 const std::optional<StringRefNull> menu_path = CTX_data_string_get(C, "asset_catalog_path");
84 if (!menu_path) {
85 return;
86 }
87 const Span<asset_system::AssetRepresentation *> assets = tree.assets_per_path.lookup(
88 menu_path->data());
89 const asset_system::AssetCatalogTreeItem *catalog_item = tree.catalogs.find_item(
90 menu_path->data());
91 BLI_assert(catalog_item != nullptr);
92
93 if (assets.is_empty() && !catalog_item->has_children()) {
94 return;
95 }
96
97 uiLayout *layout = menu->layout;
98 layout->separator();
99
100 wmOperatorType *ot = WM_operatortype_find("OBJECT_OT_modifier_add_node_group", true);
101 for (const asset_system::AssetRepresentation *asset : assets) {
102 PointerRNA props_ptr = layout->op(
103 ot, IFACE_(asset->get_name()), ICON_NONE, WM_OP_INVOKE_DEFAULT, UI_ITEM_NONE);
105 }
106
107 catalog_item->foreach_child([&](const asset_system::AssetCatalogTreeItem &item) {
108 asset::draw_menu_for_catalog(item, "OBJECT_MT_add_modifier_catalog_assets", *layout);
109 });
110}
111
112static bool unassigned_local_poll(const Main &bmain)
113{
114 LISTBASE_FOREACH (const bNodeTree *, group, &bmain.nodetrees) {
115 /* Assets are displayed in other menus, and non-local data-blocks aren't added to this menu. */
116 if (group->id.library_weak_reference || group->id.asset_data) {
117 continue;
118 }
119 if (!group->geometry_node_asset_traits ||
120 !(group->geometry_node_asset_traits->flag & GEO_NODE_ASSET_MODIFIER))
121 {
122 continue;
123 }
124 return true;
125 }
126 return false;
127}
128
129static void unassigned_assets_draw(const bContext *C, Menu *menu)
130{
131 Main &bmain = *CTX_data_main(C);
133 uiLayout *layout = menu->layout;
134 wmOperatorType *ot = WM_operatortype_find("OBJECT_OT_modifier_add_node_group", true);
135 for (const asset_system::AssetRepresentation *asset : tree.unassigned_assets) {
136 PointerRNA props_ptr = layout->op(
137 ot, IFACE_(asset->get_name()), ICON_NONE, WM_OP_INVOKE_DEFAULT, UI_ITEM_NONE);
139 }
140
141 bool first = true;
142 bool add_separator = !tree.unassigned_assets.is_empty();
143 LISTBASE_FOREACH (const bNodeTree *, group, &bmain.nodetrees) {
144 /* Assets are displayed in other menus, and non-local data-blocks aren't added to this menu. */
145 if (group->id.library_weak_reference || group->id.asset_data) {
146 continue;
147 }
148 if (!group->geometry_node_asset_traits ||
149 !(group->geometry_node_asset_traits->flag & GEO_NODE_ASSET_MODIFIER))
150 {
151 continue;
152 }
153
154 if (add_separator) {
155 layout->separator();
156 add_separator = false;
157 }
158 if (first) {
159 layout->label(IFACE_("Non-Assets"), ICON_NONE);
160 first = false;
161 }
162
163 PointerRNA props_ptr = layout->op(
164 ot, group->id.name + 2, ICON_NONE, WM_OP_INVOKE_DEFAULT, UI_ITEM_NONE);
165 WM_operator_properties_id_lookup_set_from_id(&props_ptr, &group->id);
166 }
167}
168
169static void root_catalogs_draw(const bContext *C, Menu *menu)
170{
171 const Object *object = context_active_object(C);
172 if (!object) {
173 return;
174 }
175 uiLayout *layout = menu->layout;
176
177 const bool loading_finished = all_loading_finished();
178
181 if (tree.catalogs.is_empty() && loading_finished) {
182 return;
183 }
184
185 layout->separator();
186
187 if (!loading_finished) {
188 layout->label(IFACE_("Loading Asset Libraries"), ICON_INFO);
189 }
190
191 Set<std::string> all_builtin_menus = [&]() {
192 Set<std::string> menus;
194 menus.add_new("Edit");
195 }
197 menus.add_new("Generate");
198 }
200 menus.add_new("Deform");
201 }
202 if (ELEM(object->type, OB_MESH)) {
203 menus.add_new("Normals");
204 }
206 menus.add_new("Physics");
207 }
208 return menus;
209 }();
210
211 tree.catalogs.foreach_root_item([&](const asset_system::AssetCatalogTreeItem &item) {
212 if (!all_builtin_menus.contains(item.get_name())) {
213 asset::draw_menu_for_catalog(item, "OBJECT_MT_add_modifier_catalog_assets", *layout);
214 }
215 });
216
217 if (!tree.unassigned_assets.is_empty() || unassigned_local_poll(*CTX_data_main(C))) {
218 layout->separator();
219 layout->menu(
220 "OBJECT_MT_add_modifier_unassigned_assets", IFACE_("Unassigned"), ICON_FILE_HIDDEN);
221 }
222}
223
227{
228 Main &bmain = *CTX_data_main(&C);
229 if (bNodeTree *group = reinterpret_cast<bNodeTree *>(
231 {
232 return group;
233 }
234
237 if (!asset) {
238 return nullptr;
239 }
240 return reinterpret_cast<bNodeTree *>(asset::asset_local_id_ensure_imported(bmain, *asset));
241}
242
244{
246 if (!node_group) {
247 return nullptr;
248 }
249 if (node_group->type != NTREE_GEOMETRY) {
250 if (reports) {
251 BKE_report(reports, RPT_ERROR, "Asset is not a geometry node group");
252 }
253 return nullptr;
254 }
255 return node_group;
256}
257
259{
260 Main *bmain = CTX_data_main(C);
261 Scene *scene = CTX_data_scene(C);
262
264 if (objects.is_empty()) {
265 return OPERATOR_CANCELLED;
266 }
267
268 bNodeTree *node_group = get_node_group(*C, *op->ptr, op->reports);
269 if (!node_group) {
270 return OPERATOR_CANCELLED;
271 }
272
273 bool changed = false;
274 for (const PointerRNA &ptr : objects) {
275 Object *object = static_cast<Object *>(ptr.data);
276 NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(
277 modifier_add(op->reports, bmain, scene, object, nullptr, eModifierType_Nodes));
278 if (!nmd) {
279 continue;
280 }
281 changed = true;
282 nmd->node_group = node_group;
283 id_us_plus(&node_group->id);
284 MOD_nodes_update_interface(object, nmd);
285
286 /* Don't show the data-block selector since it's not usually necessary for assets. */
288
289 STRNCPY(nmd->modifier.name, DATA_(node_group->id.name + 2));
290 BKE_modifier_unique_name(&object->modifiers, &nmd->modifier);
291
293 }
294
295 if (!changed) {
296 return OPERATOR_CANCELLED;
297 }
298
299 return OPERATOR_FINISHED;
300}
301
303 wmOperator *op,
304 const wmEvent *event)
305{
306 if (event->modifier & KM_ALT || CTX_wm_view3d(C)) {
307 RNA_boolean_set(op->ptr, "use_selected_objects", true);
308 }
309 return modifier_add_asset_exec(C, op);
310}
311
313 wmOperatorType * /*ot*/,
315{
318 if (!asset) {
319 return "";
320 }
321 if (!asset->get_metadata().description) {
322 return "";
323 }
324 return TIP_(asset->get_metadata().description);
325}
326
328{
329 ot->name = "Add Modifier";
330 ot->description = "Add a procedural operation/effect to the active object";
331 ot->idname = "OBJECT_OT_modifier_add_node_group";
332
336 ot->get_description = modifier_add_asset_get_description;
337
339
343}
344
346{
347 MenuType type{};
348 STRNCPY(type.idname, "OBJECT_MT_add_modifier_unassigned_assets");
351 type.description = N_(
352 "Modifier node group assets not assigned to a catalog.\n"
353 "Catalogs can be assigned in the Asset Browser");
354 return type;
355}
356
358{
359 MenuType type{};
360 STRNCPY(type.idname, "OBJECT_MT_add_modifier_catalog_assets");
364 return type;
365}
366
368{
369 MenuType type{};
370 STRNCPY(type.idname, "OBJECT_MT_modifier_add_root_catalogs");
374 return type;
375}
376
384
386{
388 const asset_system::AssetCatalogTreeItem *item = tree.catalogs.find_root_item(catalog_path);
389 if (!item) {
390 return;
391 }
394 if (!all_library) {
395 return;
396 }
397 layout.separator();
398 uiLayout *col = &layout.column(false);
399 uiLayoutSetContextString(col, "asset_catalog_path", item->catalog_path().str());
400 uiItemMContents(col, "OBJECT_MT_add_modifier_catalog_assets");
401}
402
403} // namespace blender::ed::object
Main runtime representation of an asset.
IDProperty * BKE_asset_metadata_idprop_find(const AssetMetaData *asset_data, const char *name) ATTR_WARN_UNUSED_RESULT
Definition asset.cc:179
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
std::optional< blender::StringRefNull > CTX_data_string_get(const bContext *C, const char *member)
View3D * CTX_wm_view3d(const bContext *C)
#define IDP_Int(prop)
void id_us_plus(ID *id)
Definition lib_id.cc:353
void BKE_modifier_unique_name(ListBase *modifiers, ModifierData *md)
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:126
#define BLI_assert(a)
Definition BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
#define ELEM(...)
#define TIP_(msgid)
#define IFACE_(msgid)
#define DATA_(msgid)
@ ID_NT
@ NODES_MODIFIER_HIDE_DATABLOCK_SELECTOR
@ eModifierType_Nodes
@ GEO_NODE_ASSET_MODIFIER
@ NTREE_GEOMETRY
@ OB_LATTICE
@ OB_SURF
@ OB_FONT
@ OB_MESH
@ OB_VOLUME
@ OB_CURVES_LEGACY
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
bool ED_operator_object_active_editable(bContext *C)
void MOD_nodes_update_interface(Object *object, NodesModifierData *nmd)
Definition MOD_nodes.cc:448
#define C
Definition RandGen.cpp:29
void uiLayoutSetContextString(uiLayout *layout, blender::StringRef name, blender::StringRef value)
#define UI_ITEM_NONE
void uiItemMContents(uiLayout *layout, blender::StringRef menuname)
@ KM_ALT
Definition WM_types.hh:277
#define ND_MODIFIER
Definition WM_types.hh:459
ReportList * reports
Definition WM_types.hh:1025
@ WM_OP_INVOKE_DEFAULT
Definition WM_types.hh:238
#define NC_OBJECT
Definition WM_types.hh:376
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
bool contains(const Key &key) const
Definition BLI_set.hh:310
void add_new(const Key &key)
Definition BLI_set.hh:233
constexpr bool is_empty() const
Definition BLI_span.hh:260
bool is_empty() const
void foreach_child(ItemIterFn callback) const
KDTree_3d * tree
uint col
#define FILTER_ID_NT
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
AssetLibraryReference all_library_reference()
void all_library_reload_catalogs_if_dirty()
asset_system::AssetLibrary * library_get_once_available(const AssetLibraryReference &library_reference)
bool is_loaded(const AssetLibraryReference *library_reference)
void asset_reading_region_listen_fn(const wmRegionListenerParams *params)
AssetItemTree build_filtered_all_catalog_tree(const AssetLibraryReference &library_ref, const bContext &C, const AssetFilterSettings &filter_settings, FunctionRef< bool(const AssetMetaData &)> meta_data_filter={})
ID * asset_local_id_ensure_imported(Main &bmain, const asset_system::AssetRepresentation &asset)
void operator_asset_reference_props_register(StructRNA &srna)
void draw_menu_for_catalog(const asset_system::AssetCatalogTreeItem &item, const StringRefNull menu_name, uiLayout &layout)
const asset_system::AssetRepresentation * operator_asset_reference_props_get_asset_from_all_library(const bContext &C, PointerRNA &ptr, ReportList *reports)
void operator_asset_reference_props_set(const asset_system::AssetRepresentation &asset, PointerRNA &ptr)
static void root_catalogs_draw(const bContext *C, Menu *menu)
void modifier_register_use_selected_objects_prop(wmOperatorType *ot)
ModifierData * modifier_add(ReportList *reports, Main *bmain, Scene *scene, Object *ob, const char *name, int type)
static void catalog_assets_draw(const bContext *C, Menu *menu)
static wmOperatorStatus modifier_add_asset_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static bNodeTree * get_asset_or_local_node_group(const bContext &C, PointerRNA &ptr, ReportList *reports)
static void OBJECT_OT_modifier_add_node_group(wmOperatorType *ot)
static wmOperatorStatus modifier_add_asset_exec(bContext *C, wmOperator *op)
static void unassigned_assets_draw(const bContext *C, Menu *menu)
static asset::AssetItemTree * get_static_item_tree()
static MenuType modifier_add_root_catalogs_menu_type()
void ui_template_modifier_asset_menu_items(uiLayout &layout, StringRef catalog_path)
static bNodeTree * get_node_group(const bContext &C, PointerRNA &ptr, ReportList *reports)
static bool unassigned_local_poll(const Main &bmain)
static MenuType modifier_add_unassigned_assets_menu_type()
static MenuType modifier_add_catalog_assets_menu_type()
static bool all_loading_finished()
static std::string modifier_add_asset_get_description(bContext *C, wmOperatorType *, PointerRNA *ptr)
static asset::AssetItemTree build_catalog_tree(const bContext &C)
Object * context_active_object(const bContext *C)
Vector< PointerRNA > modifier_get_edit_objects(const bContext &C, const wmOperator &op)
void RNA_boolean_set(PointerRNA *ptr, const char *name, bool value)
The meta-data of an asset. By creating and giving this for a data-block (ID.asset_data),...
char name[66]
Definition DNA_ID.h:415
ListBase nodetrees
Definition BKE_main.hh:270
MenuTypeFlag flag
const char * description
char idname[BKE_ST_MAXNAME]
void(* draw)(const bContext *C, Menu *menu)
void(* listener)(const wmRegionListenerParams *params)
uiLayout * layout
struct bNodeTree * node_group
PointerRNA op(wmOperatorType *ot, std::optional< blender::StringRef > name, int icon, wmOperatorCallContext context, eUI_Item_Flag flag)
void label(blender::StringRef name, int icon)
uiLayout & column(bool align)
void separator(float factor=1.0f, LayoutSeparatorType type=LayoutSeparatorType::Auto)
void menu(MenuType *mt, std::optional< blender::StringRef > name, int icon)
wmEventModifierFlag modifier
Definition WM_types.hh:771
struct ReportList * reports
struct PointerRNA * ptr
#define N_(msgid)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
PointerRNA * ptr
Definition wm_files.cc:4227
wmOperatorType * ot
Definition wm_files.cc:4226
bool WM_menutype_add(MenuType *mt)
ID * WM_operator_properties_id_lookup_from_name_or_session_uid(Main *bmain, PointerRNA *ptr, const ID_Type type)
void WM_operator_properties_id_lookup(wmOperatorType *ot, const bool add_name_prop)
void WM_operator_properties_id_lookup_set_from_id(PointerRNA *ptr, const ID *id)
void WM_operatortype_append(void(*opfunc)(wmOperatorType *))
wmOperatorType * WM_operatortype_find(const char *idname, bool quiet)