Blender V5.0
clipboard.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 "DNA_space_types.h"
6
7#include "BLI_listbase.h"
8
9#include "BKE_context.hh"
10#include "BKE_global.hh"
11#include "BKE_lib_id.hh"
12#include "BKE_lib_query.hh"
13#include "BKE_library.hh"
14#include "BKE_main.hh"
15#include "BKE_main_idmap.hh"
17#include "BKE_node.hh"
18#include "BKE_node_runtime.hh"
19#include "BKE_report.hh"
20
21#include "ED_node.hh"
22#include "ED_render.hh"
23#include "ED_screen.hh"
24
25#include "RNA_access.hh"
26#include "RNA_define.hh"
27
29
30#include "node_intern.hh"
31
33
36 std::string id_name;
44 std::string library_path;
45
49 std::optional<IDHash> packed_id_hash;
50
52 std::optional<ID *> new_id = {};
53};
54
62
63 /* Extra info to validate the IDs used by the node on creation. Otherwise it may reference
64 * missing data. */
65
67 std::string id_name;
68 std::string library_name;
69
71 bool was_active = false;
72};
73
75 const bNode *from_node = nullptr;
76 const bNode *to_node = nullptr;
77 std::string from_socket;
78 std::string to_socket;
79 int flag = 0;
81};
82
86
87 /* A mapping of all ID references from nodes in the clipboard, to information allowing to find
88 * their valid matching counterpart in current Main data when pasting the nodes back. Entries are
89 * added when adding nodes to the clipboard, and they are updated when pasting the nodes back
90 * into current Main. */
92
94 void clear()
95 {
96 for (NodeClipboardItem &item : this->nodes) {
97 bke::node_free_node(nullptr, *item.node);
98 }
99 this->nodes.clear_and_shrink();
100 this->links.clear_and_shrink();
101 this->old_ids_to_idinfo.clear();
102 }
103
114 {
115 bool is_valid = true;
116 IDNameLib_Map *bmain_id_map = nullptr;
117
118 /* Clear any potentially previously found `new_id` valid pointers in #old_ids_to_idinfo values,
119 * and populate a temporary mapping from absolute library paths to existing Library IDs in
120 * given Main. */
121 Map<std::string, Library *> libraries_path_to_id;
122 for (NodeClipboardItemIDInfo &id_info : this->old_ids_to_idinfo.values()) {
123 id_info.new_id.reset();
124 if (!id_info.packed_id_hash.has_value() && !id_info.library_path.empty() &&
125 !libraries_path_to_id.contains(id_info.library_path))
126 {
127 libraries_path_to_id.add(
128 id_info.library_path,
129 blender::bke::library::search_filepath_abs(&bmain.libraries, id_info.library_path));
130 }
131 }
132
133 /* Prepare a map of packed IDs, to avoid quadratic lookups below. */
134 Map<IDHash, ID *> packed_id_by_hash;
135 {
136 ID *id;
137 FOREACH_MAIN_ID_BEGIN (&bmain, id) {
138 if (ID_IS_PACKED(id)) {
139 packed_id_by_hash.add(id->deep_hash, id);
140 }
141 }
143 }
144
145 /* Find a new valid ID pointer for all ID usages in given node.
146 *
147 * NOTE: Due to the fact that the clipboard survives file loading, only name (including IDType)
148 * and library-path pairs can be used here.
149 * - UID cannot be trusted across file load.
150 * - ID pointer itself cannot be trusted across undo/redo and file-load. */
151 auto validate_id_fn =
152 [this, &is_valid, &bmain, &bmain_id_map, &libraries_path_to_id, &packed_id_by_hash](
153 LibraryIDLinkCallbackData *cb_data) -> int {
154 ID *old_id = *(cb_data->id_pointer);
155 if (!old_id) {
156 return IDWALK_RET_NOP;
157 }
158 if (!this->old_ids_to_idinfo.contains(old_id)) {
160 0, "Missing entry in the old ID data of the node clipboard, should not happen");
161 is_valid = false;
162 return IDWALK_RET_NOP;
163 }
164
165 NodeClipboardItemIDInfo &id_info = this->old_ids_to_idinfo.lookup(old_id);
166 if (!id_info.new_id) {
167 if (!bmain_id_map) {
168 bmain_id_map = BKE_main_idmap_create(&bmain, false, nullptr, MAIN_IDMAP_TYPE_NAME);
169 }
170 if (id_info.packed_id_hash.has_value()) {
171 id_info.new_id = packed_id_by_hash.lookup_default(*id_info.packed_id_hash, nullptr);
172 }
173 else {
174 Library *new_id_lib = libraries_path_to_id.lookup_default(id_info.library_path, nullptr);
175 BLI_assert(!new_id_lib || !(new_id_lib->flag & LIBRARY_FLAG_IS_ARCHIVE));
176 if (id_info.library_path.empty() || new_id_lib) {
177 id_info.new_id = BKE_main_idmap_lookup_name(bmain_id_map,
178 GS(id_info.id_name.c_str()),
179 id_info.id_name.c_str() + 2,
180 new_id_lib);
181 }
182 else {
183 /* No matching library found, so there is no possible matching ID either. */
184 id_info.new_id = nullptr;
185 }
186 }
187 }
188 if (*(id_info.new_id) == nullptr) {
189 is_valid = false;
190 }
191 return IDWALK_RET_NOP;
192 };
193 for (NodeClipboardItem &item : this->nodes) {
195 &bmain,
196 nullptr,
197 nullptr,
198 [&item](LibraryForeachIDData *data) { bke::node_node_foreach_id(item.node, data); },
199 validate_id_fn,
200 nullptr,
202 }
203
204 if (bmain_id_map) {
205 BKE_main_idmap_destroy(bmain_id_map);
206 bmain_id_map = nullptr;
207 }
208 return is_valid;
209 }
210
216 {
217 /* Update all old ID pointers in given node by new, valid ones. */
218 auto update_id_fn = [this](LibraryIDLinkCallbackData *cb_data) -> int {
219 ID *old_id = *(cb_data->id_pointer);
220 if (!old_id) {
221 return IDWALK_RET_NOP;
222 }
223 if (!this->old_ids_to_idinfo.contains(old_id)) {
225 0, "Missing entry in the old ID data of the node clipboard, should not happen");
226 *(cb_data->id_pointer) = nullptr;
227 return IDWALK_RET_NOP;
228 }
229
230 NodeClipboardItemIDInfo &id_info = this->old_ids_to_idinfo.lookup(old_id);
231 if (!id_info.new_id) {
233 0,
234 "Unset new ID value for an old ID reference in the node clipboard, should not happen");
235 *(cb_data->id_pointer) = nullptr;
236 return IDWALK_RET_NOP;
237 }
238 *(cb_data->id_pointer) = *(id_info.new_id);
239 if (cb_data->cb_flag & IDWALK_CB_USER) {
240 id_us_plus(*(cb_data->id_pointer));
241 }
242 return IDWALK_RET_NOP;
243 };
245 nullptr,
246 nullptr,
247 nullptr,
249 update_id_fn,
250 nullptr,
251 IDWALK_NOP);
252 }
253
255 void copy_add_node(const bNode &node,
258 {
259 /* No ID reference-counting, this node is virtual,
260 * detached from any actual Blender data currently. */
261 bNode *new_node = bke::node_copy_with_mapping(nullptr,
262 node,
265 node.name,
266 node.identifier,
267 socket_map);
268 node_map.add_new(&node, new_node);
269
270 /* Find a new valid ID pointer for all ID usages in given node. */
271 auto ensure_id_info_fn = [this](LibraryIDLinkCallbackData *cb_data) -> int {
272 ID *old_id = *(cb_data->id_pointer);
273 if (!old_id) {
274 return IDWALK_RET_NOP;
275 }
276 if (this->old_ids_to_idinfo.contains(old_id)) {
277 return IDWALK_RET_NOP;
278 }
279
281 if (old_id) {
282 id_info.id_name = old_id->name;
283 if (ID_IS_LINKED(old_id)) {
284 id_info.library_path = old_id->lib->runtime->filepath_abs;
285 if (ID_IS_PACKED(old_id)) {
286 id_info.packed_id_hash = old_id->deep_hash;
287 }
288 }
289 }
290 this->old_ids_to_idinfo.add(old_id, std::move(id_info));
291 return IDWALK_RET_NOP;
292 };
294 nullptr,
295 nullptr,
296 nullptr,
297 [&node](LibraryForeachIDData *data) {
298 bke::node_node_foreach_id(const_cast<bNode *>(&node), data);
299 },
300 ensure_id_info_fn,
301 nullptr,
303
305 item.draw_rect = node.runtime->draw_bounds;
306 item.node = new_node;
307 item.was_active = node.flag & NODE_ACTIVE;
308 this->nodes.append(std::move(item));
309 }
310};
311
313{
314 static NodeClipboard clipboard;
315 return clipboard;
316}
317
318/* -------------------------------------------------------------------- */
321
323{
324 SpaceNode &snode = *CTX_wm_space_node(C);
325 bNodeTree &tree = *snode.edittree;
326 NodeClipboard &clipboard = get_node_clipboard();
327
328 clipboard.clear();
329
332
334
335 for (const bNode *node : tree.all_nodes()) {
336 if (node->flag & SELECT) {
337 clipboard.copy_add_node(*node, node_map, socket_map);
338 }
339 }
340
341 for (bNode *new_node : node_map.values()) {
342 /* Parent pointer must be redirected to new node or detached if parent is not copied. */
343 if (new_node->parent) {
344 if (node_map.contains(new_node->parent)) {
345 new_node->parent = node_map.lookup(new_node->parent);
346 }
347 else {
348 bke::node_detach_node(tree, *new_node);
349 }
350 }
351 }
352
353 /* Copy links between selected nodes. */
354 LISTBASE_FOREACH (bNodeLink *, link, &tree.links) {
355 BLI_assert(link->tonode);
356 BLI_assert(link->fromnode);
357 if (link->tonode->flag & NODE_SELECT && link->fromnode->flag & NODE_SELECT) {
358 clipboard.links.append({});
359 ClipboardLink &new_link = clipboard.links.last();
360 new_link.flag = link->flag;
361 new_link.to_node = node_map.lookup(link->tonode);
362 new_link.from_node = node_map.lookup(link->fromnode);
363 new_link.to_socket = link->tosock->identifier;
364 new_link.from_socket = link->fromsock->identifier;
365 new_link.multi_input_sort_id = link->multi_input_sort_id;
366 }
367 }
368
369 return OPERATOR_FINISHED;
370}
371
373{
374 ot->name = "Copy to Clipboard";
375 ot->description = "Copy the selected nodes to the internal clipboard";
376 ot->idname = "NODE_OT_clipboard_copy";
377
380
382}
383
385
386/* -------------------------------------------------------------------- */
389
391{
392 Main *bmain = CTX_data_main(C);
393 SpaceNode &snode = *CTX_wm_space_node(C);
394 bNodeTree &tree = *snode.edittree;
395 NodeClipboard &clipboard = get_node_clipboard();
396
397 if (clipboard.nodes.is_empty()) {
398 BKE_report(op->reports, RPT_ERROR, "The internal clipboard is empty");
399 return OPERATOR_CANCELLED;
400 }
401
402 if (!clipboard.paste_validate_id_references(*bmain)) {
405 "Some nodes references to other IDs could not be restored, will be left empty");
406 }
407
409
411
414
415 bNode *new_active_node = nullptr;
416
417 /* copy valid nodes from clipboard */
418 for (NodeClipboardItem &item : clipboard.nodes) {
419 const bNode &node = *item.node;
420 const char *disabled_hint = nullptr;
421
422 /* Some poll functions (e.g. for the nodegroup node, see #node_group_poll_instance) do require
423 * fully valid node data, including the potential ID pointers. So first create the new copy of
424 * the clipboard node, make it as valid as possible, then call its #poll_instance function, and
425 * discard the new copy if it fails.
426 *
427 * See also #141415.
428 */
429
430 /* Do not access referenced ID pointers here, as they are still the old ones, which may be
431 * invalid. */
433 &tree, node, LIB_ID_CREATE_NO_USER_REFCOUNT, std::nullopt, std::nullopt, socket_map);
434 /* Update the newly copied node's ID references. */
435 clipboard.paste_update_node_id_references(*new_node);
436 /* Reset socket shape in case a node is copied to a different tree type. */
437 LISTBASE_FOREACH (bNodeSocket *, socket, &new_node->inputs) {
438 socket->display_shape = SOCK_DISPLAY_SHAPE_CIRCLE;
439 }
440 LISTBASE_FOREACH (bNodeSocket *, socket, &new_node->outputs) {
441 socket->display_shape = SOCK_DISPLAY_SHAPE_CIRCLE;
442 }
443
444 if (!new_node->typeinfo->poll_instance ||
445 new_node->typeinfo->poll_instance(new_node, &tree, &disabled_hint))
446 {
447 node_map.add_new(&node, new_node);
448 if (item.was_active) {
449 new_active_node = new_node;
450 }
451 }
452 else {
453 if (disabled_hint) {
455 RPT_ERROR,
456 "Cannot add node %s into node tree %s: %s",
457 node.name,
458 tree.id.name + 2,
459 disabled_hint);
460 }
461 else {
463 RPT_ERROR,
464 "Cannot add node %s into node tree %s",
465 node.name,
466 tree.id.name + 2);
467 }
468 bke::node_free_node(&tree, *new_node);
469 }
470 }
471
472 for (bNode *new_node : node_map.values()) {
473 bke::node_set_selected(*new_node, true);
474
475 new_node->flag &= ~NODE_ACTIVE;
476
477 /* The parent pointer must be redirected to new node. */
478 if (new_node->parent) {
479 if (node_map.contains(new_node->parent)) {
480 new_node->parent = node_map.lookup(new_node->parent);
481 }
482 }
483 }
484
485 if (new_active_node) {
486 bke::node_set_active(tree, *new_active_node);
487 }
488
489 PropertyRNA *offset_prop = RNA_struct_find_property(op->ptr, "offset");
490 if (RNA_property_is_set(op->ptr, offset_prop)) {
491 float2 center(0);
492 for (NodeClipboardItem &item : clipboard.nodes) {
493 center.x += BLI_rctf_cent_x(&item.draw_rect);
494 center.y += BLI_rctf_cent_y(&item.draw_rect);
495 }
496 /* DPI factor needs to be removed when computing a View2D offset from drawing rects. */
497 center /= clipboard.nodes.size();
498
499 float2 mouse_location;
500 RNA_property_float_get_array(op->ptr, offset_prop, mouse_location);
501 const float2 offset = (mouse_location - center) / UI_SCALE_FAC;
502
503 for (bNode *new_node : node_map.values()) {
504 new_node->location[0] += offset.x;
505 new_node->location[1] += offset.y;
506 }
507 }
508
509 remap_node_pairing(tree, node_map);
510
511 for (bNode *new_node : node_map.values()) {
513 }
514
515 /* Add links between existing nodes. */
516 for (const ClipboardLink &link : clipboard.links) {
517 bNode *from_node = node_map.lookup_default(link.from_node, nullptr);
518 bNode *to_node = node_map.lookup_default(link.to_node, nullptr);
519 if (!from_node || !to_node) {
520 continue;
521 }
522 bNodeSocket *from = bke::node_find_socket(*from_node, SOCK_OUT, link.from_socket.c_str());
523 bNodeSocket *to = bke::node_find_socket(*to_node, SOCK_IN, link.to_socket.c_str());
524 if (!from || !to) {
525 continue;
526 }
527 bNodeLink &new_link = bke::node_add_link(tree, *from_node, *from, *to_node, *to);
529 }
530
531 tree.ensure_topology_cache();
532 for (bNode *new_node : node_map.values()) {
533 /* Update multi input socket indices in case all connected nodes weren't copied. */
535 }
536
538 /* Pasting nodes can create arbitrary new relations because nodes can reference IDs. */
540
541 return OPERATOR_FINISHED;
542}
543
545 wmOperator *op,
546 const wmEvent *event)
547{
548 const ARegion *region = CTX_wm_region(C);
549 float2 cursor;
550 UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &cursor.x, &cursor.y);
551 RNA_float_set_array(op->ptr, "offset", cursor);
552 return node_clipboard_paste_exec(C, op);
553}
554
556{
557 ot->name = "Paste from Clipboard";
558 ot->description = "Paste nodes from the internal clipboard to the active node tree";
559 ot->idname = "NODE_OT_clipboard_paste";
560
564
566
568 ot->srna,
569 "offset",
570 2,
571 nullptr,
572 -FLT_MAX,
573 FLT_MAX,
574 "Location",
575 "The 2D view location for the center of the new nodes, or unchanged if not set",
576 -FLT_MAX,
577 FLT_MAX);
580}
581
583
584} // namespace blender::ed::space_node
585
587{
588 using namespace blender::ed::space_node;
589 NodeClipboard &clipboard = get_node_clipboard();
590 clipboard.clear();
591}
SpaceNode * CTX_wm_space_node(const bContext *C)
Main * CTX_data_main(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
void id_us_plus(ID *id)
Definition lib_id.cc:358
@ LIB_ID_CREATE_NO_USER_REFCOUNT
@ LIB_ID_CREATE_NO_MAIN
@ IDWALK_RET_NOP
@ IDWALK_CB_USER
void BKE_library_foreach_subdata_id(Main *bmain, ID *owner_id, ID *self_id, blender::FunctionRef< void(LibraryForeachIDData *data)> subdata_foreach_id, blender::FunctionRef< LibraryIDLinkCallback > callback, void *user_data, const LibraryForeachIDFlag flag)
Definition lib_query.cc:451
@ IDWALK_NOP
@ IDWALK_READONLY
#define FOREACH_MAIN_ID_END
Definition BKE_main.hh:583
#define FOREACH_MAIN_ID_BEGIN(_bmain, _id)
Definition BKE_main.hh:577
IDNameLib_Map * BKE_main_idmap_create(Main *bmain, bool create_valid_ids_set, Main *old_bmain, int idmap_types) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition main_idmap.cc:77
void BKE_main_idmap_destroy(IDNameLib_Map *id_map) ATTR_NONNULL()
ID * BKE_main_idmap_lookup_name(IDNameLib_Map *id_map, short id_type, const char *name, const Library *lib) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
@ MAIN_IDMAP_TYPE_NAME
void BKE_main_ensure_invariants(Main &bmain, std::optional< blender::Span< ID * > > modified_ids=std::nullopt)
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
@ RPT_ERROR
Definition BKE_report.hh:39
@ RPT_WARNING
Definition BKE_report.hh:38
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:153
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE float BLI_rctf_cent_y(const struct rctf *rct)
Definition BLI_rect.h:189
BLI_INLINE float BLI_rctf_cent_x(const struct rctf *rct)
Definition BLI_rect.h:185
void DEG_relations_tag_update(Main *bmain)
#define ID_IS_PACKED(_id)
Definition DNA_ID.h:700
#define ID_IS_LINKED(_id)
Definition DNA_ID.h:694
@ LIBRARY_FLAG_IS_ARCHIVE
Definition DNA_ID.h:593
@ NODE_ACTIVE
@ NODE_SELECT
@ SOCK_OUT
@ SOCK_IN
@ SOCK_DISPLAY_SHAPE_CIRCLE
#define UI_SCALE_FAC
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
void ED_preview_kill_jobs(wmWindowManager *wm, Main *bmain)
bool ED_operator_node_editable(bContext *C)
bool ED_operator_node_active(bContext *C)
@ PROP_SKIP_SAVE
Definition RNA_types.hh:344
@ PROP_HIDDEN
Definition RNA_types.hh:338
#define C
Definition RandGen.cpp:29
void UI_view2d_region_to_view(const View2D *v2d, float x, float y, float *r_view_x, float *r_view_y) ATTR_NONNULL()
Definition view2d.cc:1668
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
void clear()
Definition BLI_map.hh:1038
ValueIterator values() const &
Definition BLI_map.hh:884
bool add(const Key &key, const Value &value)
Definition BLI_map.hh:295
const Value & lookup(const Key &key) const
Definition BLI_map.hh:545
Value lookup_default(const Key &key, const Value &default_value) const
Definition BLI_map.hh:570
void add_new(const Key &key, const Value &value)
Definition BLI_map.hh:265
bool contains(const Key &key) const
Definition BLI_map.hh:353
void append(const T &value)
void clear_and_shrink()
void ED_node_clipboard_free()
Definition clipboard.cc:586
#define SELECT
KDTree_3d * tree
#define GS(x)
Library * search_filepath_abs(ListBase *libraries, blender::StringRef filepath_abs)
Definition library.cc:417
bNodeSocket * node_find_socket(bNode &node, eNodeSocketInOut in_out, StringRef identifier)
Definition node.cc:2532
void node_node_foreach_id(bNode *node, LibraryForeachIDData *data)
Definition node.cc:357
void node_free_node(bNodeTree *tree, bNode &node)
Definition node.cc:4302
bool node_set_selected(bNode &node, bool select)
Definition node.cc:4695
void node_detach_node(bNodeTree &ntree, bNode &node)
Definition node.cc:3986
bNodeLink & node_add_link(bNodeTree &ntree, bNode &fromnode, bNodeSocket &fromsock, bNode &tonode, bNodeSocket &tosock)
Definition node.cc:3810
bNode * node_copy_with_mapping(bNodeTree *dst_tree, const bNode &node_src, int flag, std::optional< StringRefNull > dst_unique_name, std::optional< int > dst_unique_identifier, Map< const bNodeSocket *, bNodeSocket * > &new_socket_map, bool allow_duplicate_names=false)
Definition node.cc:3553
bool node_declaration_ensure(bNodeTree &ntree, bNode &node)
Definition node.cc:4818
void node_set_active(bNodeTree &ntree, bNode &node)
Definition node.cc:4724
void NODE_OT_clipboard_copy(wmOperatorType *ot)
Definition clipboard.cc:372
NodeLinkData data[NODELINK_GROUP_SIZE]
Definition drawnode.cc:1863
void node_select_paired(bNodeTree &node_tree)
bool node_deselect_all(bNodeTree &node_tree)
void NODE_OT_clipboard_paste(wmOperatorType *ot)
Definition clipboard.cc:555
static wmOperatorStatus node_clipboard_paste_exec(bContext *C, wmOperator *op)
Definition clipboard.cc:390
static wmOperatorStatus node_clipboard_copy_exec(bContext *C, wmOperator *)
Definition clipboard.cc:322
void remap_node_pairing(bNodeTree &dst_tree, const Map< const bNode *, bNode * > &node_map)
static NodeClipboard & get_node_clipboard()
Definition clipboard.cc:312
void update_multi_input_indices_for_removed_links(bNode &node)
static wmOperatorStatus node_clipboard_paste_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition clipboard.cc:544
VecBase< float, 2 > float2
void RNA_property_float_get_array(PointerRNA *ptr, PropertyRNA *prop, float *values)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
void RNA_float_set_array(PointerRNA *ptr, const char *name, const float *values)
PropertyRNA * RNA_def_float_array(StructOrFunctionRNA *cont_, const char *identifier, const int len, const float *default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
#define FLT_MAX
Definition stdcycles.h:14
Definition DNA_ID.h:414
struct Library * lib
Definition DNA_ID.h:420
char name[258]
Definition DNA_ID.h:432
IDHash deep_hash
Definition DNA_ID.h:474
uint16_t flag
Definition DNA_ID.h:555
LibraryRuntimeHandle * runtime
Definition DNA_ID.h:579
ListBase libraries
Definition BKE_main.hh:279
struct bNodeTree * edittree
bNodeTypeHandle * typeinfo
ListBase inputs
char name[64]
bNodeRuntimeHandle * runtime
ListBase outputs
int32_t identifier
Vector< NodeClipboardItem > nodes
Definition clipboard.cc:84
void paste_update_node_id_references(bNode &node)
Definition clipboard.cc:215
bool paste_validate_id_references(Main &bmain)
Definition clipboard.cc:113
Map< ID *, NodeClipboardItemIDInfo > old_ids_to_idinfo
Definition clipboard.cc:91
Vector< ClipboardLink > links
Definition clipboard.cc:85
void copy_add_node(const bNode &node, Map< const bNode *, bNode * > &node_map, Map< const bNodeSocket *, bNodeSocket * > &socket_map)
Definition clipboard.cc:255
int mval[2]
Definition WM_types.hh:763
struct ReportList * reports
struct PointerRNA * ptr
wmOperatorType * ot
Definition wm_files.cc:4237