Blender V5.0
space_node.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2008 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
10
12#include "BLI_listbase.h"
13#include "BLI_math_vector.h"
14#include "BLI_stack.hh"
15#include "BLI_string.h"
16#include "BLI_string_utf8.h"
17
18#include "DNA_ID.h"
20#include "DNA_material_types.h"
21#include "DNA_modifier_types.h"
22#include "DNA_node_types.h"
23#include "DNA_object_types.h"
24#include "DNA_screen_types.h"
25#include "DNA_space_types.h"
27
28#include "MEM_guardedalloc.h"
29
30#include "BKE_asset.hh"
33#include "BKE_context.hh"
34#include "BKE_gpencil_legacy.h"
35#include "BKE_idprop.hh"
36#include "BKE_lib_id.hh"
37#include "BKE_lib_query.hh"
38#include "BKE_lib_remap.hh"
40#include "BKE_node_runtime.hh"
42#include "BKE_screen.hh"
43
44#include "BLT_translation.hh"
45
46#include "ED_asset_shelf.hh"
47#include "ED_image.hh"
48#include "ED_node.hh"
49#include "ED_node_preview.hh"
50#include "ED_screen.hh"
51#include "ED_space_api.hh"
52
53#include "UI_view2d.hh"
54
55#include "DEG_depsgraph.hh"
57
58#include "BLO_read_write.hh"
59
60#include "RNA_access.hh"
61#include "RNA_define.hh"
62#include "RNA_enum_types.hh"
63#include "RNA_prototypes.hh"
64
65#include "WM_api.hh"
66#include "WM_types.hh"
67
68#include "NOD_trace_values.hh"
69
70#include "io_utils.hh"
71
72#include "node_intern.hh" /* own include */
73
74using blender::float2;
75
76/* ******************** tree path ********************* */
77
78void ED_node_tree_start(ARegion *region, SpaceNode *snode, bNodeTree *ntree, ID *id, ID *from)
79{
81 MEM_freeN(path);
82 }
84
85 if (ntree) {
86 bNodeTreePath *path = MEM_callocN<bNodeTreePath>("node tree path");
87 path->nodetree = ntree;
89
90 /* Set initial view center from node tree. */
91 copy_v2_v2(path->view_center, ntree->view_center);
92 if (region) {
93 UI_view2d_center_set(&region->v2d, ntree->view_center[0], ntree->view_center[1]);
94 }
95
96 if (id) {
97 STRNCPY_UTF8(path->display_name, id->name + 2);
98 }
99
100 BLI_addtail(&snode->treepath, path);
101
102 if (ntree->type != NTREE_GEOMETRY) {
103 /* This can probably be removed for all node tree types. It mainly exists because it was not
104 * possible to store id references in custom properties. Also see #36024. I don't want to
105 * remove it for all tree types in bcon3 though. */
106 id_us_ensure_real(&ntree->id);
107 }
108 }
109
110 /* update current tree */
111 snode->nodetree = snode->edittree = ntree;
112 snode->id = id;
113 snode->from = from;
114
116 snode->runtime->node_can_sync_states.clear();
117
119}
120
121void ED_node_tree_push(ARegion *region, SpaceNode *snode, bNodeTree *ntree, bNode *gnode)
122{
123 bNodeTreePath *path = MEM_callocN<bNodeTreePath>("node tree path");
124 bNodeTreePath *prev_path = (bNodeTreePath *)snode->treepath.last;
125 path->nodetree = ntree;
126 if (gnode) {
127 if (prev_path) {
129 prev_path->parent_key, prev_path->nodetree, gnode);
130 }
131 else {
133 }
134
135 STRNCPY_UTF8(path->node_name, gnode->name);
136 STRNCPY_UTF8(path->display_name, gnode->name);
137 }
138 else {
140 }
141
142 /* Set initial view center from node tree. */
143 copy_v2_v2(path->view_center, ntree->view_center);
144 if (region) {
145 UI_view2d_center_set(&region->v2d, ntree->view_center[0], ntree->view_center[1]);
146 }
147
148 BLI_addtail(&snode->treepath, path);
149
150 id_us_ensure_real(&ntree->id);
151
152 /* update current tree */
153 snode->edittree = ntree;
154
156 snode->runtime->node_can_sync_states.clear();
157
159}
160
161void ED_node_tree_pop(ARegion *region, SpaceNode *snode)
162{
163 bNodeTreePath *path = (bNodeTreePath *)snode->treepath.last;
164
165 /* don't remove root */
166 if (path == snode->treepath.first) {
167 return;
168 }
169
170 BLI_remlink(&snode->treepath, path);
171 MEM_freeN(path);
172
173 /* update current tree */
174 path = (bNodeTreePath *)snode->treepath.last;
175 snode->edittree = path->nodetree;
176
177 /* Set view center from node tree path. */
178 if (region) {
179 UI_view2d_center_set(&region->v2d, path->view_center[0], path->view_center[1]);
180 }
181
183 snode->runtime->node_can_sync_states.clear();
184
186}
187
189{
190 return BLI_listbase_count(&snode->treepath);
191}
192
194{
195 bNodeTreePath *path;
196 int i;
197 for (path = (bNodeTreePath *)snode->treepath.last, i = 0; path; path = path->prev, i++) {
198 if (i == level) {
199 return path->nodetree;
200 }
201 }
202 return nullptr;
203}
204
206{
207 int length = 0;
208 int i = 0;
209 LISTBASE_FOREACH_INDEX (bNodeTreePath *, path, &snode->treepath, i) {
210 length += strlen(path->display_name);
211 if (i > 0) {
212 length += 1; /* for separator char */
213 }
214 }
215 return length;
216}
217
218void ED_node_tree_path_get(SpaceNode *snode, char *value)
219{
220 int i = 0;
221#ifndef NDEBUG
222 const char *value_orig = value;
223#endif
224 /* Note that the caller ensures there is enough space available. */
225 LISTBASE_FOREACH_INDEX (bNodeTreePath *, path, &snode->treepath, i) {
226 const int len = strlen(path->display_name);
227 if (i != 0) {
228 *value++ = '/';
229 }
230 memcpy(value, path->display_name, len);
231 value += len;
232 }
233 *value = '\0';
234 BLI_assert(ptrdiff_t(ED_node_tree_path_length(snode)) == ptrdiff_t(value - value_orig));
235}
236
238{
239 bNodeTreePath *path = (bNodeTreePath *)snode->treepath.last;
240 if (snode->nodetree && path) {
241 /* A change in active viewer may result in the change of the output node used by the
242 * compositor, so we need to get notified about such changes. */
243 if (snode->nodetree->active_viewer_key.value != path->parent_key.value &&
244 snode->nodetree->type == NTREE_COMPOSIT)
245 {
248 }
249
250 snode->nodetree->active_viewer_key = path->parent_key;
251 }
252}
253
254void ED_node_cursor_location_get(const SpaceNode *snode, float value[2])
255{
256 copy_v2_v2(value, snode->runtime->cursor);
257}
258
259void ED_node_cursor_location_set(SpaceNode *snode, const float value[2])
260{
261 copy_v2_v2(snode->runtime->cursor, value);
262}
263
264namespace blender::ed::space_node {
265
267{
268 const bNodeTreePath *path = (bNodeTreePath *)snode.treepath.last;
269
270 if (path && path->prev) {
271 return float2(path->view_center) - float2(path->prev->view_center);
272 }
273 return float2(0);
274}
275
276std::optional<nodes::FoundNestedNodeID> find_nested_node_id_in_root(const SpaceNode &snode,
277 const bNode &query_node)
278{
279 BLI_assert(snode.edittree->runtime->nodes_by_id.contains(const_cast<bNode *>(&query_node)));
280 bke::ComputeContextCache compute_context_cache;
281 const ComputeContext *compute_context = compute_context_for_edittree_node(
282 snode, compute_context_cache, query_node);
283 if (!compute_context) {
284 return {};
285 }
286 return find_nested_node_id_in_root(*snode.nodetree, compute_context, query_node.identifier);
287}
288
289std::optional<nodes::FoundNestedNodeID> find_nested_node_id_in_root(
290 const bNodeTree &root_tree, const ComputeContext *compute_context, const int node_id)
291{
293 Vector<int> node_ids;
294 for (const ComputeContext *context = compute_context; context != nullptr;
295 context = context->parent())
296 {
297 if (const auto *node_context = dynamic_cast<const bke::GroupNodeComputeContext *>(context)) {
298 node_ids.append(node_context->node_id());
299 }
300 else if (dynamic_cast<const bke::RepeatZoneComputeContext *>(context) != nullptr) {
301 found.is_in_loop = true;
302 }
303 else if (dynamic_cast<const bke::SimulationZoneComputeContext *>(context) != nullptr) {
304 found.is_in_simulation = true;
305 }
306 else if (dynamic_cast<const bke::ForeachGeometryElementZoneComputeContext *>(context) !=
307 nullptr)
308 {
309 found.is_in_loop = true;
310 }
311 else if (dynamic_cast<const bke::EvaluateClosureComputeContext *>(context) != nullptr) {
312 found.is_in_closure = true;
313 }
314 }
315 std::reverse(node_ids.begin(), node_ids.end());
316 node_ids.append(node_id);
317 const bNestedNodeRef *nested_node_ref = root_tree.nested_node_ref_from_node_id_path(node_ids);
318 if (nested_node_ref == nullptr) {
319 return std::nullopt;
320 }
321 found.id = nested_node_ref->id;
322 return found;
323}
324
325std::optional<ObjectAndModifier> get_modifier_for_node_editor(const SpaceNode &snode)
326{
328 return std::nullopt;
329 }
330 if (snode.id == nullptr) {
331 return std::nullopt;
332 }
333 if (GS(snode.id->name) != ID_OB) {
334 return std::nullopt;
335 }
336 const Object *object = reinterpret_cast<Object *>(snode.id);
337 const NodesModifierData *used_modifier = nullptr;
338 if (snode.flag & SNODE_PIN) {
339 LISTBASE_FOREACH (const ModifierData *, md, &object->modifiers) {
340 if (md->type == eModifierType_Nodes) {
341 const NodesModifierData *nmd = reinterpret_cast<const NodesModifierData *>(md);
342 /* Would be good to store the name of the pinned modifier in the node editor. */
343 if (nmd->node_group == snode.nodetree) {
344 used_modifier = nmd;
345 break;
346 }
347 }
348 }
349 }
350 else {
351 LISTBASE_FOREACH (const ModifierData *, md, &object->modifiers) {
352 if (md->type == eModifierType_Nodes) {
353 const NodesModifierData *nmd = reinterpret_cast<const NodesModifierData *>(md);
354 if (nmd->node_group == snode.nodetree) {
355 if (md->flag & eModifierFlag_Active) {
356 used_modifier = nmd;
357 break;
358 }
359 }
360 }
361 }
362 }
363 if (used_modifier == nullptr) {
364 return std::nullopt;
365 }
366 return ObjectAndModifier{object, used_modifier};
367}
368
370 const Object &object,
371 const NodesModifierData &nmd)
372{
373 const std::optional<ObjectAndModifier> object_and_modifier = get_modifier_for_node_editor(snode);
374 if (!object_and_modifier) {
375 return false;
376 }
377 const Object *object_orig = DEG_is_original(&object) ? &object : DEG_get_original(&object);
378 if (object_and_modifier->object != object_orig) {
379 return false;
380 }
381 return object_and_modifier->nmd->modifier.persistent_uid == nmd.modifier.persistent_uid;
382}
383
385 bke::ComputeContextCache &compute_context_cache,
386 const ComputeContext *parent_compute_context)
387{
388 const bNode *output_node_ptr = zone.output_node();
389 if (!output_node_ptr) {
390 return nullptr;
391 }
392 const bNode &output_node = *output_node_ptr;
393 switch (output_node.type_legacy) {
395 return &compute_context_cache.for_simulation_zone(parent_compute_context, output_node);
396 }
398 const auto &storage = *static_cast<const NodeGeometryRepeatOutput *>(output_node.storage);
399 return &compute_context_cache.for_repeat_zone(
400 parent_compute_context, output_node, storage.inspection_index);
401 }
403 const auto &storage = *static_cast<const NodeGeometryForeachGeometryElementOutput *>(
404 output_node.storage);
405 return &compute_context_cache.for_foreach_geometry_element_zone(
406 parent_compute_context, output_node, storage.inspection_index);
407 }
408 case NODE_CLOSURE_OUTPUT: {
409 nodes::ClosureSourceLocation source_location{};
410 const bNodeTree &tree = output_node.owner_tree();
411 source_location.tree = &tree;
412 source_location.closure_output_node_id = output_node.identifier;
413 source_location.compute_context_hash = parent_compute_context ?
414 parent_compute_context->hash() :
416 source_location.compute_context = parent_compute_context;
417 return compute_context_for_closure_evaluation(parent_compute_context,
418 output_node.output_socket(0),
419 compute_context_cache,
420 source_location);
421 }
422 }
423 return nullptr;
424}
425
427 bke::ComputeContextCache &compute_context_cache,
428 const ComputeContext *parent_compute_context)
429{
430 const ComputeContext *current = parent_compute_context;
431 for (const bke::bNodeTreeZone *zone : zones) {
432 current = compute_context_for_zone(*zone, compute_context_cache, current);
433 if (!current) {
434 return nullptr;
435 }
436 }
437 return current;
438}
439
440static std::optional<const ComputeContext *> compute_context_for_tree_path(
441 const SpaceNode &snode,
442 bke::ComputeContextCache &compute_context_cache,
443 const ComputeContext *parent_compute_context)
444{
445 const ComputeContext *current = parent_compute_context;
447 LISTBASE_FOREACH (const bNodeTreePath *, item, &snode.treepath) {
448 tree_path.append(item);
449 }
450 if (tree_path.is_empty()) {
451 return current;
452 }
453
454 for (const int i : tree_path.index_range().drop_back(1)) {
455 bNodeTree *tree = tree_path[i]->nodetree;
456 const char *group_node_name = tree_path[i + 1]->node_name;
457 const bNode *group_node = blender::bke::node_find_node_by_name(*tree, group_node_name);
458 if (group_node == nullptr) {
459 return std::nullopt;
460 }
461 const blender::bke::bNodeTreeZones *tree_zones = tree->zones();
462 if (tree_zones == nullptr) {
463 return std::nullopt;
464 }
467 tree_zones->get_zone_by_node(group_node->identifier));
468 current = compute_context_for_zones(zone_stack, compute_context_cache, current);
469 if (!current) {
470 return std::nullopt;
471 }
472 current = &compute_context_cache.for_group_node(current, group_node->identifier, tree);
473 }
474 return current;
475}
476
478 const SpaceNode &snode, bke::ComputeContextCache &compute_context_cache)
479{
480 if (snode.nodetree->type == NTREE_GEOMETRY) {
483 std::optional<ed::space_node::ObjectAndModifier> object_and_modifier =
485 if (!object_and_modifier) {
486 return nullptr;
487 }
488 return &compute_context_cache.for_modifier(nullptr, *object_and_modifier->nmd);
489 }
490 case SNODE_GEOMETRY_TOOL: {
491 return &compute_context_cache.for_operator(nullptr);
492 }
493 }
494 return nullptr;
495 }
496 if (snode.nodetree->type == NTREE_SHADER) {
497 return &compute_context_cache.for_shader(nullptr, snode.nodetree);
498 }
499 return nullptr;
500}
501
503 const SpaceNode &snode, bke::ComputeContextCache &compute_context_cache)
504{
505 if (!snode.edittree) {
506 return nullptr;
507 }
509 return nullptr;
510 }
511 const ComputeContext *root_context = get_node_editor_root_compute_context(snode,
512 compute_context_cache);
513 if (!root_context) {
514 return nullptr;
515 }
516 const ComputeContext *edittree_context =
517 compute_context_for_tree_path(snode, compute_context_cache, root_context).value_or(nullptr);
518 return edittree_context;
519}
520
522 const SpaceNode &snode,
523 bke::ComputeContextCache &compute_context_cache,
524 const bNodeSocket &socket)
525{
526 const ComputeContext *context = compute_context_for_edittree(snode, compute_context_cache);
527 if (!context) {
528 return nullptr;
529 }
530 const bke::bNodeTreeZones *zones = snode.edittree->zones();
531 if (!zones) {
532 return nullptr;
533 }
534 const bke::bNodeTreeZone *zone = zones->get_zone_by_socket(socket);
536 return compute_context_for_zones(zone_stack, compute_context_cache, context);
537}
538
540 const SpaceNode &snode, bke::ComputeContextCache &compute_context_cache, const bNode &node)
541{
542 const ComputeContext *context = compute_context_for_edittree(snode, compute_context_cache);
543 if (!context) {
544 return nullptr;
545 }
546 const bke::bNodeTreeZones *zones = snode.edittree->zones();
547 if (!zones) {
548 return nullptr;
549 }
550 const bke::bNodeTreeZone *zone = zones->get_zone_by_node(node.identifier);
552 return compute_context_for_zones(zone_stack, compute_context_cache, context);
553}
554
555/* ******************** default callbacks for node space ***************** */
556
557static SpaceLink *node_create(const ScrArea * /*area*/, const Scene * /*scene*/)
558{
559 SpaceNode *snode = MEM_callocN<SpaceNode>(__func__);
560 snode->runtime = MEM_new<SpaceNode_Runtime>(__func__);
561 snode->spacetype = SPACE_NODE;
562
566
567 /* backdrop */
568 snode->zoom = 1.0f;
569
570 /* select the first tree type for valid type */
571 for (const bke::bNodeTreeType *treetype : bke::node_tree_types_get()) {
572 STRNCPY_UTF8(snode->tree_idname, treetype->idname.c_str());
573 break;
574 }
575
576 /* header */
577 ARegion *region = BKE_area_region_new();
578
579 BLI_addtail(&snode->regionbase, region);
580 region->regiontype = RGN_TYPE_HEADER;
582
583 /* asset shelf */
584 region = BKE_area_region_new();
585
586 BLI_addtail(&snode->regionbase, region);
588 region->alignment = RGN_ALIGN_BOTTOM;
589 region->flag |= RGN_FLAG_HIDDEN;
590
591 /* asset shelf header */
592 region = BKE_area_region_new();
593
594 BLI_addtail(&snode->regionbase, region);
597
598 /* buttons/list view */
599 region = BKE_area_region_new();
600
601 BLI_addtail(&snode->regionbase, region);
602 region->regiontype = RGN_TYPE_UI;
603 region->alignment = RGN_ALIGN_RIGHT;
604
605 /* toolbar */
606 region = BKE_area_region_new();
607
608 BLI_addtail(&snode->regionbase, region);
609 region->regiontype = RGN_TYPE_TOOLS;
610 region->alignment = RGN_ALIGN_LEFT;
611
612 region->flag = RGN_FLAG_HIDDEN;
613
614 /* main region */
615 region = BKE_area_region_new();
616
617 BLI_addtail(&snode->regionbase, region);
618 region->regiontype = RGN_TYPE_WINDOW;
619
620 region->v2d.tot.xmin = -12.8f * U.widget_unit;
621 region->v2d.tot.ymin = -12.8f * U.widget_unit;
622 region->v2d.tot.xmax = 38.4f * U.widget_unit;
623 region->v2d.tot.ymax = 38.4f * U.widget_unit;
624
625 region->v2d.cur = region->v2d.tot;
626
627 region->v2d.min[0] = 1.0f;
628 region->v2d.min[1] = 1.0f;
629
630 region->v2d.max[0] = 32000.0f;
631 region->v2d.max[1] = 32000.0f;
632
633 region->v2d.minzoom = 0.05f;
634 region->v2d.maxzoom = 2.31f;
635
638 region->v2d.keeptot = 0;
639
640 return (SpaceLink *)snode;
641}
642
643static void node_free(SpaceLink *sl)
644{
645 SpaceNode *snode = (SpaceNode *)sl;
646 BLI_freelistN(&snode->treepath);
647 MEM_delete(snode->runtime);
648}
649
650/* spacetype; init callback */
651static void node_init(wmWindowManager * /*wm*/, ScrArea * /*area*/) {}
652
654{
655 SpaceNode *snode = static_cast<SpaceNode *>(area->spacedata.first);
656
657 if (snode->runtime) {
658 free_previews(*wm, *snode);
659 }
660}
661
662static bool any_node_uses_id(const bNodeTree *ntree, const ID *id)
663{
664 if (ELEM(nullptr, ntree, id)) {
665 return false;
666 }
667 for (const bNode *node : ntree->all_nodes()) {
668 if (node->id == id) {
669 return true;
670 }
671 }
672 return false;
673}
674
684{
685 if (ED_node_is_compositor(snode)) {
686 snode->runtime->recalc_regular_compositing = true;
687 }
688
690}
691
693{
694 ScrArea *area = params->area;
695 const wmNotifier *wmn = params->notifier;
696
697 /* NOTE: #ED_area_tag_refresh will re-execute compositor. */
698 SpaceNode *snode = static_cast<SpaceNode *>(area->spacedata.first);
699 /* shaderfrom is only used for new shading nodes, otherwise all shaders are from objects */
700 short shader_type = snode->shaderfrom;
701
702 /* preview renders */
703 switch (wmn->category) {
704 case NC_SCENE:
705 switch (wmn->data) {
706 case ND_NODES: {
707 node_area_tag_tree_recalc(snode, area);
708 break;
709 }
710 case ND_FRAME:
711 node_area_tag_tree_recalc(snode, area);
712 break;
713 case ND_COMPO_RESULT: {
714 ED_area_tag_redraw(area);
715 /* Backdrop image offset is calculated during compositing so gizmos need to be updated
716 * afterwards. */
718 WM_gizmomap_tag_refresh(region->runtime->gizmo_map);
719 break;
720 }
721 }
722 break;
723
724 /* future: add ID checks? */
725 case NC_MATERIAL:
726 if (ED_node_is_shader(snode)) {
727 if (wmn->data == ND_SHADING) {
728 node_area_tag_tree_recalc(snode, area);
729 }
730 else if (wmn->data == ND_SHADING_DRAW) {
731 node_area_tag_tree_recalc(snode, area);
732 }
733 else if (wmn->data == ND_SHADING_LINKS) {
734 node_area_tag_tree_recalc(snode, area);
735 }
736 }
737 break;
738 case NC_TEXTURE:
739 if (ED_node_is_shader(snode) || ED_node_is_texture(snode)) {
740 if (wmn->data == ND_NODES) {
741 node_area_tag_tree_recalc(snode, area);
742 }
743 }
744 break;
745 case NC_WORLD:
746 if (ED_node_is_shader(snode) && shader_type == SNODE_SHADER_WORLD) {
747 node_area_tag_tree_recalc(snode, area);
748 }
749 break;
750 case NC_OBJECT:
751 if (ED_node_is_shader(snode)) {
752 if (wmn->data == ND_OB_SHADING) {
753 node_area_tag_tree_recalc(snode, area);
754 }
755 }
756 else if (ED_node_is_geometry(snode)) {
757 if (wmn->data == ND_MODIFIER) {
758 /* Rather strict check: only redraw when the reference matches current editor's ID, */
759 if (wmn->reference == snode->id || snode->id == nullptr) {
760 node_area_tag_tree_recalc(snode, area);
761 }
762 /* Redraw context path or modifier dependent information. */
763 ED_area_tag_redraw(area);
764 }
765 }
766 break;
767 case NC_SPACE:
768 if (wmn->data == ND_SPACE_NODE) {
769 node_area_tag_tree_recalc(snode, area);
770 }
771 else if (wmn->data == ND_SPACE_NODE_VIEW) {
772 ED_area_tag_redraw(area);
773 }
774 break;
775 case NC_NODE:
776 if (wmn->action == NA_EDITED) {
777 if (ELEM(wmn->reference, snode->nodetree, snode->id, nullptr) || snode->id == nullptr) {
778 node_area_tag_tree_recalc(snode, area);
779 }
780 }
781 else if (wmn->action == NA_SELECTED) {
782 ED_area_tag_redraw(area);
783 }
784 break;
785 case NC_SCREEN:
786 switch (wmn->data) {
787 case ND_ANIMPLAY:
788 node_area_tag_tree_recalc(snode, area);
789 break;
790 }
791 break;
792 case NC_MASK:
793 if (wmn->action == NA_EDITED) {
794 if (snode->nodetree && snode->nodetree->type == NTREE_COMPOSIT) {
795 node_area_tag_tree_recalc(snode, area);
796 }
797 }
798 break;
799
800 case NC_IMAGE:
801 if (wmn->action == NA_EDITED) {
802 if (ED_node_is_compositor(snode)) {
803 /* Without this check drawing on an image could become very slow when the compositor is
804 * open. */
805 if (any_node_uses_id(snode->nodetree, (ID *)wmn->reference)) {
806 node_area_tag_tree_recalc(snode, area);
807 }
808 }
809 }
810 break;
811
812 case NC_MOVIECLIP:
813 if (wmn->action == NA_EDITED) {
814 if (ED_node_is_compositor(snode)) {
815 if (any_node_uses_id(snode->nodetree, (ID *)wmn->reference)) {
816 node_area_tag_tree_recalc(snode, area);
817 }
818 }
819 }
820 break;
821
822 case NC_LINESTYLE:
823 if (ED_node_is_shader(snode) && shader_type == SNODE_SHADER_LINESTYLE) {
824 node_area_tag_tree_recalc(snode, area);
825 }
826 break;
827 case NC_WM:
828 if (wmn->data == ND_UNDO) {
829 node_area_tag_tree_recalc(snode, area);
830 }
831 break;
832 case NC_GPENCIL:
833 if (ELEM(wmn->action, NA_EDITED, NA_SELECTED)) {
834 ED_area_tag_redraw(area);
835 }
836 break;
837 }
838}
839
840static void node_area_refresh(const bContext *C, ScrArea *area)
841{
842 /* default now: refresh node is starting preview */
843 SpaceNode *snode = static_cast<SpaceNode *>(area->spacedata.first);
844
846
847 Scene *scene = CTX_data_scene(C);
848 if (snode->nodetree && snode->nodetree == scene->compositing_node_group) {
850 snode->runtime->recalc_regular_compositing = false;
852 }
853 }
854}
855
857{
858 SpaceNode *snode = (SpaceNode *)sl;
859 SpaceNode *snoden = (SpaceNode *)MEM_dupallocN(snode);
860
861 BLI_duplicatelist(&snoden->treepath, &snode->treepath);
862
863 snoden->runtime = MEM_new<SpaceNode_Runtime>(__func__);
864
865 /* NOTE: no need to set node tree user counts,
866 * the editor only keeps at least 1 (id_us_ensure_real),
867 * which is already done by the original SpaceNode.
868 */
869
870 return (SpaceLink *)snoden;
871}
872
873/* add handlers, stuff you only do once or on area/region changes */
875{
876 wmKeyMap *keymap;
877
878 ED_region_panels_init(wm, region);
879
880 keymap = WM_keymap_ensure(wm->runtime->defaultconf, "Node Generic", SPACE_NODE, RGN_TYPE_WINDOW);
881 WM_event_add_keymap_handler(&region->runtime->handlers, keymap);
882}
883
884static void node_buttons_region_draw(const bContext *C, ARegion *region)
885{
886 ED_region_panels(C, region);
887}
888
889/* add handlers, stuff you only do once or on area/region changes */
891{
892 wmKeyMap *keymap;
893
894 ED_region_panels_init(wm, region);
895
896 keymap = WM_keymap_ensure(wm->runtime->defaultconf, "Node Generic", SPACE_NODE, RGN_TYPE_WINDOW);
897 WM_event_add_keymap_handler(&region->runtime->handlers, keymap);
898}
899
900static void node_toolbar_region_draw(const bContext *C, ARegion *region)
901{
902 ED_region_panels(C, region);
903}
904
905static void node_cursor(wmWindow *win, ScrArea *area, ARegion *region)
906{
907 SpaceNode *snode = static_cast<SpaceNode *>(area->spacedata.first);
908
909 /* convert mouse coordinates to v2d space */
911 win->eventstate->xy[0] - region->winrct.xmin,
912 win->eventstate->xy[1] - region->winrct.ymin,
913 &snode->runtime->cursor[0],
914 &snode->runtime->cursor[1]);
915
916 /* here snode->runtime->cursor is used to detect the node edge for sizing */
917 node_set_cursor(*win, *region, *snode, snode->runtime->cursor);
918
919 /* XXX snode->runtime->cursor is in placing new nodes space */
920 snode->runtime->cursor[0] /= UI_SCALE_FAC;
921 snode->runtime->cursor[1] /= UI_SCALE_FAC;
922}
923
924/* Initialize main region, setting handlers. */
926{
927 wmKeyMap *keymap;
928 ListBase *lb;
929
930 UI_view2d_region_reinit(&region->v2d, V2D_COMMONVIEW_CUSTOM, region->winx, region->winy);
931
932 /* own keymaps */
933 keymap = WM_keymap_ensure(wm->runtime->defaultconf, "Node Generic", SPACE_NODE, RGN_TYPE_WINDOW);
934 WM_event_add_keymap_handler(&region->runtime->handlers, keymap);
935
936 keymap = WM_keymap_ensure(wm->runtime->defaultconf, "Node Editor", SPACE_NODE, RGN_TYPE_WINDOW);
937 WM_event_add_keymap_handler_v2d_mask(&region->runtime->handlers, keymap);
938
939 /* add drop boxes */
940 lb = WM_dropboxmap_find("Node Editor", SPACE_NODE, RGN_TYPE_WINDOW);
941
942 WM_event_add_dropbox_handler(&region->runtime->handlers, lb);
943
944 /* The backdrop image gizmo needs to change together with the view. So always refresh gizmos on
945 * region size changes. */
946 WM_gizmomap_tag_refresh(region->runtime->gizmo_map);
947}
948
949static void node_main_region_draw(const bContext *C, ARegion *region)
950{
951 node_draw_space(*C, *region);
952}
953
954/* ************* dropboxes ************* */
955
956static bool node_group_drop_poll(bContext *C, wmDrag *drag, const wmEvent * /*event*/)
957{
958 SpaceNode *snode = CTX_wm_space_node(C);
959
960 if (snode == nullptr) {
961 return false;
962 }
963
964 if (snode->edittree == nullptr) {
965 return false;
966 }
967
968 if (!WM_drag_is_ID_type(drag, ID_NT)) {
969 return false;
970 }
971
972 if (drag->type == WM_DRAG_ID) {
973 const bNodeTree *node_tree = reinterpret_cast<const bNodeTree *>(
975 if (!node_tree) {
976 return false;
977 }
978 return node_tree->type == snode->edittree->type;
979 }
980
981 if (drag->type == WM_DRAG_ASSET) {
982 const wmDragAsset *asset_data = WM_drag_get_asset_data(drag, ID_NT);
983 if (!asset_data) {
984 return false;
985 }
986 const AssetMetaData *metadata = &asset_data->asset->get_metadata();
987 const IDProperty *tree_type = BKE_asset_metadata_idprop_find(metadata, "type");
988 if (!tree_type || IDP_int_get(tree_type) != snode->edittree->type) {
989 return false;
990 }
991 }
992
993 return true;
994}
995
996static bool node_object_drop_poll(bContext *C, wmDrag *drag, const wmEvent * /*event*/)
997{
999}
1000
1001static bool node_collection_drop_poll(bContext *C, wmDrag *drag, const wmEvent * /*event*/)
1002{
1004}
1005
1006static bool node_id_im_drop_poll(bContext * /*C*/, wmDrag *drag, const wmEvent * /*event*/)
1007{
1008 return WM_drag_is_ID_type(drag, ID_IM);
1009}
1010
1011static bool node_mask_drop_poll(bContext * /*C*/, wmDrag *drag, const wmEvent * /*event*/)
1012{
1013 return WM_drag_is_ID_type(drag, ID_MSK);
1014}
1015
1016static bool node_material_drop_poll(bContext *C, wmDrag *drag, const wmEvent * /*event*/)
1017{
1019}
1020
1021static bool node_color_drop_poll(bContext *C, wmDrag *drag, const wmEvent * /*event*/)
1022{
1023 return (drag->type == WM_DRAG_COLOR) && !UI_but_active_drop_color(C);
1024}
1025
1026static bool node_import_file_drop_poll(bContext *C, wmDrag *drag, const wmEvent * /*event*/)
1027{
1028 SpaceNode *snode = CTX_wm_space_node(C);
1029 if (!snode) {
1030 return false;
1031 }
1032 if (!snode->edittree) {
1033 return false;
1034 }
1035 if (snode->edittree->type != NTREE_GEOMETRY) {
1036 return false;
1037 }
1038 if (drag->type != WM_DRAG_PATH) {
1039 return false;
1040 }
1042 for (const StringRef path : paths) {
1043 if (path.endswith(".csv") || path.endswith(".obj") || path.endswith(".ply") ||
1044 path.endswith(".stl") || path.endswith(".txt") || path.endswith(".vdb"))
1045 {
1046 return true;
1047 }
1048 }
1049 return false;
1050}
1051
1052static bool node_socket_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
1053{
1054 if (drag->type != WM_DRAG_NODE_TREE_INTERFACE) {
1055 return false;
1056 }
1057 SpaceNode *snode = CTX_wm_space_node(C);
1058 if (!snode || !snode->edittree) {
1059 return false;
1060 }
1061 const bNodeTree *target_ntree = snode->edittree;
1062
1063 auto *drag_data = static_cast<bke::node_interface::bNodeTreeInterfaceItemReference *>(
1064 drag->poin);
1065
1066 /* Drag only onto node editors of the same node tree. */
1067 const bNodeTree *source_ntree = drag_data->tree;
1068 if (target_ntree != source_ntree) {
1069 return false;
1070 }
1071
1072 /* Accept only socket items. */
1073 const bNodeTreeInterfaceSocket *socket =
1075 if (socket) {
1076 /* The check to avoid dragging output sockets is deferred to the
1077 * operator's poll in order to display a hint tooltip. */
1078 return true;
1079 }
1080
1081 /* Unless Ctrl is held, prefer dragging the toggle socket alone from a panel with toggle. */
1082 if (!(event->modifier & KM_CTRL)) {
1083 const bNodeTreeInterfacePanel *panel =
1085 if (panel && panel->header_toggle_socket()) {
1086 return true;
1087 }
1088 }
1089 return false;
1090}
1091
1092static bool node_panel_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
1093{
1094 if (drag->type != WM_DRAG_NODE_TREE_INTERFACE) {
1095 return false;
1096 }
1097 SpaceNode *snode = CTX_wm_space_node(C);
1098 if (!snode || !snode->edittree) {
1099 return false;
1100 }
1101 const bNodeTree *target_ntree = snode->edittree;
1102
1103 auto *drag_data = static_cast<bke::node_interface::bNodeTreeInterfaceItemReference *>(
1104 drag->poin);
1105
1106 /* Drag only onto node editors of the same node. */
1107 const bNodeTree *source_ntree = drag_data->tree;
1108 if (target_ntree != source_ntree) {
1109 return false;
1110 }
1111
1112 /* Accept only panel items. */
1114 drag_data->item);
1115 if (panel) {
1116 /* Unless Ctrl is held, prefer dragging only the toggle socket of a panel with toggle. */
1117 if (!(event->modifier & KM_CTRL)) {
1118 if (panel->header_toggle_socket()) {
1119 return false;
1120 }
1121 }
1122
1123 /* The check for whether the panel contains at least one input socket is
1124 * deferred to the operator's poll in order to display a hint tooltip. */
1125 return true;
1126 }
1127 return false;
1128}
1129
1131{
1133
1134 RNA_int_set(drop->ptr, "session_uid", int(id->session_uid));
1135
1136 RNA_boolean_set(drop->ptr, "show_datablock_in_node", (drag->type != WM_DRAG_ASSET));
1137}
1138
1139static void node_id_drop_copy(bContext *C, wmDrag *drag, wmDropBox *drop)
1140{
1142
1143 RNA_int_set(drop->ptr, "session_uid", int(id->session_uid));
1144}
1145
1147{
1149 if (id) {
1150 RNA_int_set(drop->ptr, "session_uid", int(id->session_uid));
1151 RNA_struct_property_unset(drop->ptr, "filepath");
1152 return;
1153 }
1154}
1155
1156static void node_import_file_drop_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *drop)
1157{
1159}
1160
1161static void node_socket_drop_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *drop)
1162{
1163 if (drag->type != WM_DRAG_NODE_TREE_INTERFACE) {
1164 return;
1165 }
1166
1167 auto *drag_data = static_cast<bke::node_interface::bNodeTreeInterfaceItemReference *>(
1168 drag->poin);
1169 const bNodeTreeInterfaceSocket *socket =
1171 if (!socket) {
1172 const bNodeTreeInterfacePanel *panel =
1174 socket = panel->header_toggle_socket();
1175 }
1176
1177 BLI_assert(socket);
1178 PropertyRNA *prop = RNA_struct_find_property(drop->ptr, "panel_identifier");
1179 RNA_property_unset(drop->ptr, prop);
1180 RNA_string_set(drop->ptr, "socket_identifier", socket->identifier);
1181}
1182
1183static void node_panel_drop_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *drop)
1184{
1185 if (drag->type != WM_DRAG_NODE_TREE_INTERFACE) {
1186 return;
1187 }
1188
1189 auto *drag_data = static_cast<bke::node_interface::bNodeTreeInterfaceItemReference *>(
1190 drag->poin);
1192 drag_data->item);
1193
1194 BLI_assert(panel);
1195 PropertyRNA *prop = RNA_struct_find_property(drop->ptr, "socket_identifier");
1196 RNA_property_unset(drop->ptr, prop);
1197 RNA_int_set(drop->ptr, "panel_identifier", panel->identifier);
1198}
1199
1200static std::string node_socket_drop_tooltip(bContext * /*C*/,
1201 wmDrag *drag,
1202 const int /*xy*/[2],
1203 wmDropBox * /*drop*/)
1204{
1205 auto *drag_data = static_cast<bke::node_interface::bNodeTreeInterfaceItemReference *>(
1206 drag->poin);
1207 const bNodeTreeInterfaceSocket *socket =
1209
1210 if (socket) {
1211 return BLI_sprintfN(TIP_("Add \"%s\" Input"), socket->name);
1212 }
1213 else {
1214 const bNodeTreeInterfacePanel *panel =
1216 socket = panel->header_toggle_socket();
1217
1218 /* Dragging a panel with toggle defaults to dragging the toggle socket.
1219 * Display a hint with the modifier required to drag the panel. */
1220 if (socket) {
1221 return BLI_sprintfN(TIP_("Add \"%s\" Input (Ctrl to add panel)"), socket->name);
1222 }
1223 }
1225 return "Error: Unsupported socket.";
1226}
1227
1228static std::string node_panel_drop_tooltip(bContext * /*C*/,
1229 wmDrag *drag,
1230 const int /*xy*/[2],
1231 wmDropBox * /*drop*/)
1232{
1233 auto *drag_data = static_cast<bke::node_interface::bNodeTreeInterfaceItemReference *>(
1234 drag->poin);
1236 drag_data->item);
1237 BLI_assert(panel);
1238 return BLI_sprintfN(TIP_("Add \"%s\" Panel"), panel->name);
1239}
1240
1241/* this region dropbox definition */
1242static void node_dropboxes()
1243{
1245
1246 WM_dropbox_add(lb,
1247 "NODE_OT_add_object",
1251 nullptr);
1252 WM_dropbox_add(lb,
1253 "NODE_OT_add_collection",
1257 nullptr);
1258 WM_dropbox_add(lb,
1259 "NODE_OT_add_group",
1263 nullptr);
1264 WM_dropbox_add(lb,
1265 "NODE_OT_add_image",
1269 nullptr);
1270 WM_dropbox_add(lb,
1271 "NODE_OT_add_mask",
1275 nullptr);
1276 WM_dropbox_add(lb,
1277 "NODE_OT_add_material",
1281 nullptr);
1283 lb, "NODE_OT_add_color", node_color_drop_poll, UI_drop_color_copy, nullptr, nullptr);
1284 WM_dropbox_add(lb,
1285 "NODE_OT_add_import_node",
1288 nullptr,
1289 nullptr);
1290 WM_dropbox_add(lb,
1291 "NODE_OT_add_group_input_node",
1294 nullptr,
1296 WM_dropbox_add(lb,
1297 "NODE_OT_add_group_input_node",
1300 nullptr,
1302}
1303
1304/* ************* end drop *********** */
1305
1306/* add handlers, stuff you only do once or on area/region changes */
1308{
1309 ED_region_header_init(region);
1310}
1311
1312static void node_header_region_draw(const bContext *C, ARegion *region)
1313{
1314 /* find and set the context */
1316
1317 ED_region_header(C, region);
1318}
1319
1320/* used for header + main region */
1322{
1323 ARegion *region = params->region;
1324 const wmNotifier *wmn = params->notifier;
1325 wmGizmoMap *gzmap = region->runtime->gizmo_map;
1326
1327 /* context changes */
1328 switch (wmn->category) {
1329 case NC_SPACE:
1330 switch (wmn->data) {
1331 case ND_SPACE_NODE:
1332 ED_region_tag_redraw(region);
1333 break;
1334 case ND_SPACE_NODE_VIEW:
1336 break;
1337 }
1338 break;
1339 case NC_ANIMATION:
1340 if (wmn->data == ND_NLA_ACTCHANGE) {
1341 ED_region_tag_redraw(region);
1342 }
1343 break;
1344 case NC_SCREEN:
1345 if (wmn->data == ND_LAYOUTSET || wmn->action == NA_EDITED) {
1347 }
1348 switch (wmn->data) {
1349 case ND_ANIMPLAY:
1350 case ND_LAYER:
1351 ED_region_tag_redraw(region);
1352 break;
1353 }
1354 break;
1355 case NC_WM:
1356 if (wmn->data == ND_JOB) {
1357 ED_region_tag_redraw(region);
1358 }
1359 break;
1360 case NC_SCENE:
1361 ED_region_tag_redraw(region);
1362 if (wmn->data == ND_RENDER_RESULT) {
1364 }
1365 break;
1366 case NC_NODE:
1367 ED_region_tag_redraw(region);
1368 if (ELEM(wmn->action, NA_EDITED, NA_SELECTED)) {
1370 }
1371 break;
1372 case NC_MATERIAL:
1373 case NC_TEXTURE:
1374 case NC_WORLD:
1375 case NC_LINESTYLE:
1376 ED_region_tag_redraw(region);
1377 break;
1378 case NC_OBJECT:
1379 if (wmn->data == ND_OB_SHADING) {
1380 ED_region_tag_redraw(region);
1381 }
1382 break;
1383 case NC_ID:
1384 if (ELEM(wmn->action, NA_RENAME, NA_EDITED)) {
1385 ED_region_tag_redraw(region);
1386 }
1387 break;
1388 case NC_GPENCIL:
1389 if (wmn->action == NA_EDITED) {
1390 ED_region_tag_redraw(region);
1391 }
1392 else if (wmn->data & ND_GPENCIL_EDITMODE) {
1393 ED_region_tag_redraw(region);
1394 }
1395 break;
1396 case NC_VIEWER_PATH:
1397 ED_region_tag_redraw(region);
1398 break;
1399 }
1400}
1401
1402} // namespace blender::ed::space_node
1403
1404/* Outside of blender namespace to avoid Python documentation build error with `ctypes`. */
1405extern "C" {
1406const char *node_context_dir[] = {
1407 "selected_nodes", "active_node", "light", "material", "world", nullptr};
1408};
1409
1410namespace blender::ed::space_node {
1411
1412static int /*eContextResult*/ node_context(const bContext *C,
1413 const char *member,
1415{
1416 SpaceNode *snode = CTX_wm_space_node(C);
1417
1418 if (CTX_data_dir(member)) {
1420 return CTX_RESULT_OK;
1421 }
1422 if (CTX_data_equals(member, "selected_nodes")) {
1423 if (snode->edittree) {
1424 for (bNode *node : snode->edittree->all_nodes()) {
1425 if (node->flag & NODE_SELECT) {
1426 CTX_data_list_add(result, &snode->edittree->id, &RNA_Node, node);
1427 }
1428 }
1429 }
1431 return CTX_RESULT_OK;
1432 }
1433 if (CTX_data_equals(member, "active_node")) {
1434 if (snode->edittree) {
1435 bNode *node = bke::node_get_active(*snode->edittree);
1436 CTX_data_pointer_set(result, &snode->edittree->id, &RNA_Node, node);
1437 }
1438
1440 return CTX_RESULT_OK;
1441 }
1442 if (CTX_data_equals(member, "node_previews")) {
1443 if (snode->nodetree) {
1445 &snode->nodetree->id,
1446 &RNA_NodeInstanceHash,
1447 &snode->nodetree->runtime->previews);
1448 }
1449
1451 return CTX_RESULT_OK;
1452 }
1453 if (CTX_data_equals(member, "material")) {
1454 if (snode->id && GS(snode->id->name) == ID_MA) {
1456 }
1457 return CTX_RESULT_OK;
1458 }
1459 if (CTX_data_equals(member, "light")) {
1460 if (snode->id && GS(snode->id->name) == ID_LA) {
1462 }
1463 return CTX_RESULT_OK;
1464 }
1465 if (CTX_data_equals(member, "world")) {
1466 if (snode->id && GS(snode->id->name) == ID_WO) {
1468 }
1469 return CTX_RESULT_OK;
1470 }
1471
1473}
1474
1488
1489static void node_id_remap(ID *old_id, ID *new_id, SpaceNode *snode)
1490{
1491 if (snode->id == old_id) {
1492 /* nasty DNA logic for SpaceNode:
1493 * ideally should be handled by editor code, but would be bad level call
1494 */
1495 BLI_freelistN(&snode->treepath);
1496
1497 /* XXX Untested in case new_id != nullptr... */
1498 snode->id = new_id;
1499 snode->from = nullptr;
1500 snode->nodetree = nullptr;
1501 snode->edittree = nullptr;
1502 }
1503 else if (GS(old_id->name) == ID_OB) {
1504 if (snode->from == old_id) {
1505 if (new_id == nullptr) {
1506 snode->flag &= ~SNODE_PIN;
1507 }
1508 snode->from = new_id;
1509 }
1510 }
1511 else if (GS(old_id->name) == ID_GD_LEGACY) {
1512 if ((ID *)snode->gpd == old_id) {
1513 snode->gpd = (bGPdata *)new_id;
1514 id_us_min(old_id);
1515 id_us_plus(new_id);
1516 }
1517 }
1518 else if (GS(old_id->name) == ID_NT) {
1519
1520 if (snode->selected_node_group) {
1521 if (&snode->selected_node_group->id == old_id) {
1522 snode->selected_node_group = reinterpret_cast<bNodeTree *>(new_id);
1523 }
1524 }
1525
1526 bNodeTreePath *path, *path_next;
1527
1528 for (path = (bNodeTreePath *)snode->treepath.first; path; path = path->next) {
1529 if ((ID *)path->nodetree == old_id) {
1530 path->nodetree = (bNodeTree *)new_id;
1531 id_us_ensure_real(new_id);
1532 }
1533 if (path == snode->treepath.first) {
1534 /* first nodetree in path is same as snode->nodetree */
1535 snode->nodetree = path->nodetree;
1536 }
1537 if (path->nodetree == nullptr) {
1538 break;
1539 }
1540 }
1541
1542 /* remaining path entries are invalid, remove */
1543 for (; path; path = path_next) {
1544 path_next = path->next;
1545
1546 BLI_remlink(&snode->treepath, path);
1547 MEM_freeN(path);
1548 }
1549
1550 /* edittree is just the last in the path,
1551 * set this directly since the path may have been shortened above */
1552 if (snode->treepath.last) {
1553 path = (bNodeTreePath *)snode->treepath.last;
1554 snode->edittree = path->nodetree;
1556 }
1557 else {
1558 snode->edittree = nullptr;
1559 }
1560 }
1561}
1562
1563static void node_id_remap(ScrArea * /*area*/,
1564 SpaceLink *slink,
1565 const blender::bke::id::IDRemapper &mappings)
1566{
1567 /* Although we should be able to perform all the mappings in a single go this lead to issues when
1568 * running the python test cases. Somehow the nodetree/edittree weren't updated to the new
1569 * pointers that generated a SEGFAULT.
1570 *
1571 * To move forward we should perhaps remove snode->edittree and snode->nodetree as they are just
1572 * copies of pointers. All usages should be calling a function that will receive the appropriate
1573 * instance.
1574 *
1575 * We could also move a remap address at a time to use the IDRemapper as that should get closer
1576 * to cleaner code. See {D13615} for more information about this topic.
1577 */
1578 mappings.iter([&](ID *old_id, ID *new_id) {
1579 node_id_remap(old_id, new_id, reinterpret_cast<SpaceNode *>(slink));
1580 });
1581}
1582
1584{
1585 SpaceNode *snode = reinterpret_cast<SpaceNode *>(space_link);
1586 const int data_flags = BKE_lib_query_foreachid_process_flags_get(data);
1587 const bool is_readonly = (data_flags & IDWALK_READONLY) != 0;
1588 const bool allow_pointer_access = (data_flags & IDWALK_NO_ORIG_POINTERS_ACCESS) == 0;
1589 bool is_embedded_nodetree = snode->id != nullptr && allow_pointer_access &&
1590 bke::node_tree_from_id(snode->id) == snode->nodetree;
1591
1594
1595 bNodeTreePath *path = static_cast<bNodeTreePath *>(snode->treepath.first);
1596 BLI_assert(path == nullptr || path->nodetree == snode->nodetree);
1597
1598 if (is_embedded_nodetree) {
1600 if (path != nullptr) {
1602 }
1603
1604 /* Embedded ID pointers are not remapped (besides exceptions), ensure it still matches
1605 * actual data. Note that `snode->id` was already processed (and therefore potentially
1606 * remapped) above. */
1607 if (!is_readonly) {
1608 snode->nodetree = (snode->id == nullptr) ? nullptr : bke::node_tree_from_id(snode->id);
1609 if (path != nullptr) {
1610 path->nodetree = snode->nodetree;
1611 }
1612 }
1613 }
1614 else {
1617 if (path != nullptr) {
1620 }
1621 }
1622
1625
1626 /* Both `snode->id` and `snode->nodetree` have been remapped now, so their data can be
1627 * accessed. */
1628 BLI_assert(snode->id == nullptr || snode->nodetree == nullptr ||
1629 (snode->nodetree->id.flag & ID_FLAG_EMBEDDED_DATA) == 0 ||
1630 snode->nodetree == bke::node_tree_from_id(snode->id));
1631
1632 /* This is mainly here for readfile case ('lib_link' process), as in such case there is no access
1633 * to original data allowed, so no way to know whether the SpaceNode nodetree pointer is an
1634 * embedded one or not. */
1635 if (!is_readonly && snode->id && !snode->nodetree) {
1636 is_embedded_nodetree = true;
1637 snode->nodetree = bke::node_tree_from_id(snode->id);
1638 if (path != nullptr) {
1639 path->nodetree = snode->nodetree;
1640 }
1641 }
1642
1643 if (path != nullptr) {
1644 for (path = path->next; path != nullptr; path = path->next) {
1645 BLI_assert(path->nodetree != nullptr);
1646 if (allow_pointer_access) {
1648 }
1649
1652
1653 if (path->nodetree == nullptr) {
1654 BLI_assert(!is_readonly);
1655 /* Remaining path entries are invalid, remove them. */
1656 for (bNodeTreePath *path_next; path; path = path_next) {
1657 path_next = path->next;
1658 BLI_remlink(&snode->treepath, path);
1659 MEM_freeN(path);
1660 }
1661 break;
1662 }
1663 }
1664 }
1665 BLI_assert(path == nullptr);
1666
1667 if (!is_readonly) {
1668 /* `edittree` is just the last in the path, set this directly since the path may have
1669 * been shortened above. */
1670 if (snode->treepath.last != nullptr) {
1671 path = static_cast<bNodeTreePath *>(snode->treepath.last);
1672 snode->edittree = path->nodetree;
1673 }
1674 else {
1675 snode->edittree = nullptr;
1676 }
1677 }
1678 else {
1679 /* Only process this pointer in readonly case, otherwise could lead to a bad
1680 * double-remapping e.g. */
1681 if (is_embedded_nodetree && snode->edittree == snode->nodetree) {
1683 }
1684 else {
1686 }
1687 }
1688}
1689
1691{
1692 SpaceNode *snode = static_cast<SpaceNode *>(area->spacedata.first);
1694}
1695
1696static void node_space_subtype_set(ScrArea *area, int value)
1697{
1698 SpaceNode *snode = static_cast<SpaceNode *>(area->spacedata.first);
1700}
1701
1703{
1704 bool free;
1706 RNA_enum_items_add(item, totitem, item_src);
1707 if (free) {
1708 MEM_freeN(item_src);
1709 }
1710}
1711
1713{
1714 SpaceNode *snode = static_cast<SpaceNode *>(area->spacedata.first);
1716 if (tree_type == nullptr) {
1717 return IFACE_("Node Editor");
1718 }
1719 return tree_type->ui_name;
1720}
1721
1722static int node_space_icon_get(const ScrArea *area)
1723{
1724 SpaceNode *snode = static_cast<SpaceNode *>(area->spacedata.first);
1726 if (tree_type == nullptr) {
1727 return ICON_NODETREE;
1728 }
1729 return tree_type->ui_icon;
1730}
1731
1733{
1734 SpaceNode *snode = (SpaceNode *)sl;
1735
1736 if (snode->gpd) {
1737 BLO_read_struct(reader, bGPdata, &snode->gpd);
1738 BKE_gpencil_blend_read_data(reader, snode->gpd);
1739 }
1740
1742 snode->edittree = nullptr;
1743 snode->runtime = MEM_new<SpaceNode_Runtime>(__func__);
1744}
1745
1747{
1748 SpaceNode *snode = (SpaceNode *)sl;
1749 BLO_write_struct(writer, SpaceNode, snode);
1750
1751 LISTBASE_FOREACH (bNodeTreePath *, path, &snode->treepath) {
1752 BLO_write_struct(writer, bNodeTreePath, path);
1753 }
1754}
1755
1757{
1758 using namespace blender::ed;
1759 wmKeyMap *keymap = WM_keymap_ensure(
1760 wm->runtime->defaultconf, "Node Generic", SPACE_NODE, RGN_TYPE_WINDOW);
1761 WM_event_add_keymap_handler(&region->runtime->handlers, keymap);
1762
1764}
1765
1766} // namespace blender::ed::space_node
1767
1769{
1770 using namespace blender::ed;
1771 using namespace blender::ed::space_node;
1772
1773 std::unique_ptr<SpaceType> st = std::make_unique<SpaceType>();
1774 ARegionType *art;
1775
1776 st->spaceid = SPACE_NODE;
1777 STRNCPY_UTF8(st->name, "Node");
1778
1779 st->create = node_create;
1780 st->free = node_free;
1781 st->init = node_init;
1782 st->exit = node_exit;
1783 st->duplicate = node_duplicate;
1784 st->operatortypes = node_operatortypes;
1785 st->keymap = node_keymap;
1786 st->listener = node_area_listener;
1787 st->refresh = node_area_refresh;
1788 st->context = node_context;
1789 st->dropboxes = node_dropboxes;
1790 st->gizmos = node_widgets;
1791 st->id_remap = node_id_remap;
1792 st->foreach_id = node_foreach_id;
1793 st->space_subtype_item_extend = node_space_subtype_item_extend;
1794 st->space_subtype_get = node_space_subtype_get;
1795 st->space_subtype_set = node_space_subtype_set;
1796 st->space_name_get = node_space_name_get;
1797 st->space_icon_get = node_space_icon_get;
1798 st->blend_read_data = node_space_blend_read_data;
1799 st->blend_read_after_liblink = nullptr;
1800 st->blend_write = node_space_blend_write;
1801
1802 /* regions: main window */
1803 art = MEM_callocN<ARegionType>("spacetype node region");
1810 art->cursor = node_cursor;
1811 art->event_cursor = true;
1812 art->clip_gizmo_events_by_ui = true;
1814
1815 BLI_addhead(&st->regiontypes, art);
1816
1817 /* regions: header */
1818 art = MEM_callocN<ARegionType>("spacetype node region");
1820 art->prefsizey = HEADERY;
1825
1826 BLI_addhead(&st->regiontypes, art);
1827
1828 /* regions: asset shelf */
1829 art = MEM_callocN<ARegionType>("spacetype node asset shelf region");
1844 BLI_addhead(&st->regiontypes, art);
1845
1846 /* regions: asset shelf header */
1847 art = MEM_callocN<ARegionType>("spacetype node asset shelf header region");
1855 BLI_addhead(&st->regiontypes, art);
1857
1858 /* regions: list-view/buttons */
1859 art = MEM_callocN<ARegionType>("spacetype node region");
1860 art->regionid = RGN_TYPE_UI;
1868 BLI_addhead(&st->regiontypes, art);
1869
1871
1872 /* regions: toolbar */
1873 art = MEM_callocN<ARegionType>("spacetype view3d tools region");
1874 art->regionid = RGN_TYPE_TOOLS;
1875 art->prefsizex = int(UI_TOOLBAR_WIDTH);
1876 art->prefsizey = 50; /* XXX */
1883 BLI_addhead(&st->regiontypes, art);
1884
1889
1890 BKE_spacetype_register(std::move(st));
1891}
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
void CTX_data_dir_set(bContextDataResult *result, const char **dir)
bool CTX_data_equals(const char *member, const char *str)
void CTX_data_pointer_set(bContextDataResult *result, ID *id, StructRNA *type, void *data)
bool CTX_data_dir(const char *member)
void CTX_data_id_pointer_set(bContextDataResult *result, ID *id)
void CTX_data_type_set(bContextDataResult *result, ContextDataType type)
SpaceNode * CTX_wm_space_node(const bContext *C)
@ CTX_RESULT_MEMBER_NOT_FOUND
@ CTX_RESULT_OK
Scene * CTX_data_scene(const bContext *C)
void CTX_data_list_add(bContextDataResult *result, ID *id, StructRNA *type, void *data)
void BKE_gpencil_blend_read_data(struct BlendDataReader *reader, struct bGPdata *gpd)
#define IDP_int_get(prop)
void id_us_plus(ID *id)
Definition lib_id.cc:358
void id_us_ensure_real(ID *id)
Definition lib_id.cc:313
void id_us_min(ID *id)
Definition lib_id.cc:366
#define BKE_LIB_FOREACHID_PROCESS_IDSUPER(data_, id_super_, cb_flag_)
@ IDWALK_CB_USER_ONE
@ IDWALK_CB_EMBEDDED_NOT_OWNING
@ IDWALK_CB_DIRECT_WEAK_LINK
#define BKE_LIB_FOREACHID_PROCESS_ID(data_, id_, cb_flag_)
LibraryForeachIDFlag BKE_lib_query_foreachid_process_flags_get(const LibraryForeachIDData *data)
Definition lib_query.cc:129
@ IDWALK_READONLY
@ IDWALK_NO_ORIG_POINTERS_ACCESS
#define GEO_NODE_FOREACH_GEOMETRY_ELEMENT_OUTPUT
#define GEO_NODE_SIMULATION_OUTPUT
#define NODE_CLOSURE_OUTPUT
#define GEO_NODE_REPEAT_OUTPUT
void BKE_spacetype_register(std::unique_ptr< SpaceType > st)
Definition screen.cc:282
ARegion * BKE_area_region_new()
Definition screen.cc:387
ARegion * BKE_area_find_region_type(const ScrArea *area, int region_type)
Definition screen.cc:846
@ REGION_DRAW_LOCK_ALL
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
void BLI_kdtree_nd_ free(KDTree *tree)
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE void BLI_listbase_clear(ListBase *lb)
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
void void BLI_freelistN(ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:497
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
#define LISTBASE_FOREACH_INDEX(type, var, list, index_var)
void BLI_remlink(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:131
void BLI_addhead(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:91
int BLI_listbase_count(const ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:524
void void void void void void BLI_duplicatelist(ListBase *dst, const ListBase *src) ATTR_NONNULL(1
MINLINE void copy_v2_v2(float r[2], const float a[2])
char * BLI_sprintfN(const char *__restrict format,...) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_PRINTF_FORMAT(1
#define STRNCPY_UTF8(dst, src)
#define ELEM(...)
#define BLO_write_struct(writer, struct_name, data_ptr)
#define BLO_read_struct_list(reader, struct_name, list)
#define BLO_read_struct(reader, struct_name, ptr_p)
#define TIP_(msgid)
#define IFACE_(msgid)
void DEG_id_tag_update(ID *id, unsigned int flags)
bool DEG_is_original(const T *id)
T * DEG_get_original(T *id)
ID and Library types, which are fundamental for SDNA.
@ ID_RECALC_NTREE_OUTPUT
Definition DNA_ID.h:1155
@ ID_FLAG_EMBEDDED_DATA
Definition DNA_ID.h:774
@ ID_IM
@ ID_NT
@ ID_LA
@ ID_MSK
@ ID_WO
@ ID_MA
@ ID_GD_LEGACY
@ ID_GR
@ ID_OB
@ eModifierFlag_Active
@ eModifierType_Nodes
@ NODE_SELECT
@ NTREE_SHADER
@ NTREE_GEOMETRY
@ NTREE_COMPOSIT
Object is a sort of wrapper for general info.
#define HEADERY
@ RGN_ALIGN_HIDE_WITH_PREV
@ RGN_ALIGN_BOTTOM
@ RGN_ALIGN_LEFT
@ RGN_ALIGN_TOP
@ RGN_ALIGN_RIGHT
@ RGN_TYPE_UI
@ RGN_TYPE_ASSET_SHELF_HEADER
@ RGN_TYPE_WINDOW
@ RGN_TYPE_ASSET_SHELF
@ RGN_TYPE_HEADER
@ RGN_TYPE_TOOLS
@ RGN_FLAG_HIDDEN
@ SN_OVERLAY_SHOW_PATH
@ SN_OVERLAY_SHOW_PREVIEWS
@ SN_OVERLAY_SHOW_WIRE_COLORS
@ SN_OVERLAY_SHOW_OVERLAYS
@ SNODE_PIN
@ SNODE_USE_ALPHA
@ SNODE_SHOW_GPENCIL
@ SPACE_NODE
SpaceNodeGeometryNodesType
@ SNODE_GEOMETRY_MODIFIER
@ SNODE_GEOMETRY_TOOL
@ SNODE_SHADER_WORLD
@ SNODE_SHADER_LINESTYLE
#define UI_SCALE_FAC
@ USER_HEADER_BOTTOM
@ V2D_LIMITZOOM
@ V2D_KEEPASPECT
@ V2D_SCROLL_RIGHT
@ V2D_SCROLL_BOTTOM
bool ED_node_is_geometry(const SpaceNode *snode)
Definition node_edit.cc:502
void ED_node_set_tree_type(SpaceNode *snode, blender::bke::bNodeTreeType *typeinfo)
Definition node_edit.cc:473
bool ED_node_is_compositor(const SpaceNode *snode)
Definition node_edit.cc:487
void ED_node_set_active_viewer_key(SpaceNode *snode)
bool ED_node_is_shader(SpaceNode *snode)
Definition node_edit.cc:492
void ED_node_composite_job(const bContext *C, bNodeTree *nodetree, Scene *scene_owner)
Definition node_edit.cc:371
bool ED_node_is_texture(SpaceNode *snode)
Definition node_edit.cc:497
void ED_area_tag_redraw(ScrArea *area)
Definition area.cc:693
void ED_area_do_mgs_subscribe_for_tool_ui(const wmRegionMessageSubscribeParams *params)
Definition area.cc:409
void ED_region_panels(const bContext *C, ARegion *region)
Definition area.cc:3609
void ED_region_header(const bContext *C, ARegion *region)
Definition area.cc:3935
void ED_region_header_init(ARegion *region)
Definition area.cc:3950
int ED_region_generic_tools_region_snap_size(const ARegion *region, int size, int axis)
Definition area_utils.cc:40
void ED_area_tag_refresh(ScrArea *area)
Definition area.cc:722
void ED_region_generic_tools_region_message_subscribe(const wmRegionMessageSubscribeParams *params)
Definition area_utils.cc:28
int ED_region_generic_panel_region_snap_size(const ARegion *region, int size, int axis)
Definition area_utils.cc:71
void ED_region_panels_init(wmWindowManager *wm, ARegion *region)
Definition area.cc:3616
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:618
@ ED_KEYMAP_ASSET_SHELF
Definition ED_screen.hh:768
@ ED_KEYMAP_UI
Definition ED_screen.hh:758
@ ED_KEYMAP_HEADER
Definition ED_screen.hh:764
@ ED_KEYMAP_TOOL
Definition ED_screen.hh:760
@ ED_KEYMAP_GPENCIL
Definition ED_screen.hh:766
@ ED_KEYMAP_GIZMO
Definition ED_screen.hh:759
@ ED_KEYMAP_VIEW2D
Definition ED_screen.hh:761
@ ED_KEYMAP_FRAMES
Definition ED_screen.hh:763
@ ED_KEYMAP_FOOTER
Definition ED_screen.hh:765
Read Guarded memory(de)allocation.
blender::bke::bNodeTreeType * rna_node_tree_type_from_enum(int value)
int rna_node_tree_idname_to_enum(const char *idname)
const EnumPropertyItem * RNA_enum_node_tree_types_itemf_impl(bContext *C, bool *r_free)
#define C
Definition RandGen.cpp:29
#define UI_SIDEBAR_PANEL_WIDTH
bool UI_but_active_drop_name(const bContext *C)
#define UI_TOOLBAR_WIDTH
void UI_drop_color_copy(bContext *C, wmDrag *drag, wmDropBox *drop)
bool UI_but_active_drop_color(bContext *C)
void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy)
Definition view2d.cc:221
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
void UI_view2d_center_set(View2D *v2d, float x, float y)
Definition view2d.cc:1949
@ V2D_COMMONVIEW_CUSTOM
Definition UI_view2d.hh:31
#define NC_WORLD
Definition WM_types.hh:387
#define ND_SHADING
Definition WM_types.hh:477
#define NC_ID
Definition WM_types.hh:395
#define NC_NODE
Definition WM_types.hh:394
#define ND_NLA_ACTCHANGE
Definition WM_types.hh:498
@ KM_CTRL
Definition WM_types.hh:279
#define ND_RENDER_RESULT
Definition WM_types.hh:446
#define ND_JOB
Definition WM_types.hh:416
#define NC_WM
Definition WM_types.hh:374
#define ND_GPENCIL_EDITMODE
Definition WM_types.hh:504
#define NC_LINESTYLE
Definition WM_types.hh:400
#define NC_ANIMATION
Definition WM_types.hh:388
@ WM_DRAG_PATH
Definition WM_types.hh:1208
@ WM_DRAG_COLOR
Definition WM_types.hh:1218
@ WM_DRAG_NODE_TREE_INTERFACE
Definition WM_types.hh:1223
@ WM_DRAG_ASSET
Definition WM_types.hh:1202
@ WM_DRAG_ID
Definition WM_types.hh:1201
#define NC_VIEWER_PATH
Definition WM_types.hh:406
#define ND_SPACE_NODE
Definition WM_types.hh:526
#define ND_COMPO_RESULT
Definition WM_types.hh:447
#define NC_SCREEN
Definition WM_types.hh:377
#define NC_MOVIECLIP
Definition WM_types.hh:397
#define ND_ANIMPLAY
Definition WM_types.hh:424
#define NC_SCENE
Definition WM_types.hh:378
#define ND_SPACE_NODE_VIEW
Definition WM_types.hh:536
#define ND_NODES
Definition WM_types.hh:436
#define ND_MODIFIER
Definition WM_types.hh:462
#define NA_EDITED
Definition WM_types.hh:584
#define NC_MATERIAL
Definition WM_types.hh:380
#define NC_IMAGE
Definition WM_types.hh:384
#define ND_UNDO
Definition WM_types.hh:417
#define ND_FRAME
Definition WM_types.hh:434
#define NC_GPENCIL
Definition WM_types.hh:399
#define NC_TEXTURE
Definition WM_types.hh:381
#define ND_LAYER
Definition WM_types.hh:450
#define NC_MASK
Definition WM_types.hh:398
#define NA_RENAME
Definition WM_types.hh:588
#define ND_OB_SHADING
Definition WM_types.hh:457
#define ND_LAYOUTSET
Definition WM_types.hh:426
#define NC_OBJECT
Definition WM_types.hh:379
#define ND_SHADING_LINKS
Definition WM_types.hh:479
#define ND_SHADING_DRAW
Definition WM_types.hh:478
#define NC_SPACE
Definition WM_types.hh:392
#define NA_SELECTED
Definition WM_types.hh:589
#define U
const ComputeContextHash & hash() const
constexpr IndexRange drop_back(int64_t n) const
void append(const T &value)
bool is_empty() const
IndexRange index_range() const
const ModifierComputeContext & for_modifier(const ComputeContext *parent, const NodesModifierData &nmd)
const GroupNodeComputeContext & for_group_node(const ComputeContext *parent, int32_t node_id, const bNodeTree *tree=nullptr)
const ForeachGeometryElementZoneComputeContext & for_foreach_geometry_element_zone(const ComputeContext *parent, int32_t output_node_id, int index)
const RepeatZoneComputeContext & for_repeat_zone(const ComputeContext *parent, int32_t output_node_id, int iteration)
const ShaderComputeContext & for_shader(const ComputeContext *parent, const bNodeTree *tree)
const OperatorComputeContext & for_operator(const ComputeContext *parent)
const SimulationZoneComputeContext & for_simulation_zone(const ComputeContext *parent, int output_node_id)
const bNode * output_node() const
Vector< const bNodeTreeZone * > get_zones_to_enter_from_root(const bNodeTreeZone *zone) const
const bNodeTreeZone * get_zone_by_node(const int32_t node_id) const
const bNodeTreeZone * get_zone_by_socket(const bNodeSocket &socket) const
void iter(FunctionRef< void(ID *old_id, ID *new_id)> func) const
KDTree_3d * tree
#define GS(x)
float length(VecOp< float, D >) RET
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
T & get_item_as(bNodeTreeInterfaceItem &item)
bNode * node_find_node_by_name(bNodeTree &ntree, StringRefNull name)
Definition node.cc:3275
bNodeTreeType * node_tree_type_find(StringRef idname)
Definition node.cc:2303
bNode * node_get_active(bNodeTree &ntree)
Definition node.cc:4685
const bNodeInstanceKey NODE_INSTANCE_KEY_BASE
Definition node.cc:4846
bNodeInstanceKey node_instance_key(bNodeInstanceKey parent_key, const bNodeTree *ntree, const bNode *node)
Definition node.cc:4867
Span< bNodeTreeType * > node_tree_types_get()
Definition node.cc:2374
bNodeTree * node_tree_from_id(ID *id)
Definition node.cc:4568
void header_region(const bContext *C, ARegion *region)
void region_init(wmWindowManager *wm, ARegion *region)
void types_register(ARegionType *region_type, const int space_type)
void region_listen(const wmRegionListenerParams *params)
void region_on_poll_success(const bContext *C, ARegion *region)
void header_region_listen(const wmRegionListenerParams *params)
void region_on_user_resize(const ARegion *region)
int context(const bContext *C, const char *member, bContextDataResult *result)
int region_snap(const ARegion *region, int size, int axis)
void * region_duplicate(void *regiondata)
bool regions_poll(const RegionPollParams *params)
void header_region_init(wmWindowManager *wm, ARegion *region)
void region_draw(const bContext *C, ARegion *region)
void region_message_subscribe(const wmRegionMessageSubscribeParams *params)
void region_layout(const bContext *C, ARegion *region)
void region_free(ARegion *region)
void paths_to_operator_properties(PointerRNA *ptr, const Span< std::string > paths)
Definition io_utils.cc:117
static const ComputeContext * get_node_editor_root_compute_context(const SpaceNode &snode, bke::ComputeContextCache &compute_context_cache)
const ComputeContext * compute_context_for_edittree_socket(const SpaceNode &snode, bke::ComputeContextCache &compute_context_cache, const bNodeSocket &socket)
static void node_header_region_init(wmWindowManager *, ARegion *region)
static void node_widgets()
static void node_space_subtype_item_extend(bContext *C, EnumPropertyItem **item, int *totitem)
NodeLinkData data[NODELINK_GROUP_SIZE]
Definition drawnode.cc:1863
static std::string node_panel_drop_tooltip(bContext *, wmDrag *drag, const int[2], wmDropBox *)
static bool node_import_file_drop_poll(bContext *C, wmDrag *drag, const wmEvent *)
static int node_space_icon_get(const ScrArea *area)
static void node_toolbar_region_draw(const bContext *C, ARegion *region)
static void node_space_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
static void node_group_drop_copy(bContext *C, wmDrag *drag, wmDropBox *drop)
static bool node_panel_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
static void node_header_region_draw(const bContext *C, ARegion *region)
static void node_asset_shelf_region_init(wmWindowManager *wm, ARegion *region)
MenuType swap_root_catalogs_menu_type()
static void node_foreach_id(SpaceLink *space_link, LibraryForeachIDData *data)
void free_previews(wmWindowManager &wm, SpaceNode &snode)
static SpaceLink * node_duplicate(SpaceLink *sl)
static void node_main_region_init(wmWindowManager *wm, ARegion *region)
static void node_id_remap(ID *old_id, ID *new_id, SpaceNode *snode)
void node_set_cursor(wmWindow &win, ARegion &region, SpaceNode &snode, const float2 &cursor)
static void node_import_file_drop_copy(bContext *, wmDrag *drag, wmDropBox *drop)
std::optional< nodes::FoundNestedNodeID > find_nested_node_id_in_root(const SpaceNode &snode, const bNode &node)
static void node_area_refresh(const bContext *C, ScrArea *area)
void NODE_GGT_backdrop_split(wmGizmoGroupType *gzgt)
static void node_panel_drop_copy(bContext *, wmDrag *drag, wmDropBox *drop)
static bool node_material_drop_poll(bContext *C, wmDrag *drag, const wmEvent *)
static std::optional< const ComputeContext * > compute_context_for_tree_path(const SpaceNode &snode, bke::ComputeContextCache &compute_context_cache, const ComputeContext *parent_compute_context)
void NODE_GGT_backdrop_corner_pin(wmGizmoGroupType *gzgt)
void node_tree_interface_panel_register(ARegionType *art)
const ComputeContext * compute_context_for_edittree(const SpaceNode &snode, bke::ComputeContextCache &compute_context_cache)
static bool node_color_drop_poll(bContext *C, wmDrag *drag, const wmEvent *)
static bool node_mask_drop_poll(bContext *, wmDrag *drag, const wmEvent *)
static int node_space_subtype_get(ScrArea *area)
void NODE_GGT_backdrop_crop(wmGizmoGroupType *gzgt)
static bool node_group_drop_poll(bContext *C, wmDrag *drag, const wmEvent *)
const ComputeContext * compute_context_for_zone(const bke::bNodeTreeZone &zone, bke::ComputeContextCache &compute_context_cache, const ComputeContext *parent_compute_context)
static void node_region_listener(const wmRegionListenerParams *params)
static bool node_id_im_drop_poll(bContext *, wmDrag *drag, const wmEvent *)
float2 space_node_group_offset(const SpaceNode &snode)
void NODE_GGT_backdrop_box_mask(wmGizmoGroupType *gzgt)
static void node_free(SpaceLink *sl)
static bool node_collection_drop_poll(bContext *C, wmDrag *drag, const wmEvent *)
std::optional< ObjectAndModifier > get_modifier_for_node_editor(const SpaceNode &snode)
static blender::StringRefNull node_space_name_get(const ScrArea *area)
static void node_dropboxes()
void NODE_GGT_backdrop_transform(wmGizmoGroupType *gzgt)
void snode_set_context(const bContext &C)
Definition node_edit.cc:682
static void node_area_listener(const wmSpaceTypeListenerParams *params)
static void node_id_im_drop_copy(bContext *C, wmDrag *drag, wmDropBox *drop)
void node_keymap(wmKeyConfig *keyconf)
Definition node_ops.cc:128
const ComputeContext * compute_context_for_zones(const Span< const bke::bNodeTreeZone * > zones, bke::ComputeContextCache &compute_context_cache, const ComputeContext *parent_compute_context)
static std::string node_socket_drop_tooltip(bContext *, wmDrag *drag, const int[2], wmDropBox *)
void NODE_GGT_backdrop_ellipse_mask(wmGizmoGroupType *gzgt)
static void node_init(wmWindowManager *, ScrArea *)
static int node_context(const bContext *C, const char *member, bContextDataResult *result)
static bool node_object_drop_poll(bContext *C, wmDrag *drag, const wmEvent *)
void node_draw_space(const bContext &C, ARegion &region)
static void node_cursor(wmWindow *win, ScrArea *area, ARegion *region)
static void node_buttons_region_draw(const bContext *C, ARegion *region)
static void node_socket_drop_copy(bContext *, wmDrag *drag, wmDropBox *drop)
static void node_id_drop_copy(bContext *C, wmDrag *drag, wmDropBox *drop)
bool node_editor_is_for_geometry_nodes_modifier(const SpaceNode &snode, const Object &object, const NodesModifierData &nmd)
static void node_toolbar_region_init(wmWindowManager *wm, ARegion *region)
static void node_exit(wmWindowManager *wm, ScrArea *area)
const ComputeContext * compute_context_for_edittree_node(const SpaceNode &snode, bke::ComputeContextCache &compute_context_cache, const bNode &node)
static void node_main_region_draw(const bContext *C, ARegion *region)
static bool any_node_uses_id(const bNodeTree *ntree, const ID *id)
void NODE_GGT_backdrop_glare(wmGizmoGroupType *gzgt)
static void node_buttons_region_init(wmWindowManager *wm, ARegion *region)
static void node_space_blend_write(BlendWriter *writer, SpaceLink *sl)
static void node_area_tag_tree_recalc(SpaceNode *snode, ScrArea *area)
static bool node_socket_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
static SpaceLink * node_create(const ScrArea *, const Scene *)
static void node_space_subtype_set(ScrArea *area, int value)
VecBase< float, 2 > float2
const char * node_context_dir[]
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
void RNA_boolean_set(PointerRNA *ptr, const char *name, bool value)
void RNA_int_set(PointerRNA *ptr, const char *name, int value)
void RNA_struct_property_unset(PointerRNA *ptr, const char *identifier)
void RNA_property_unset(PointerRNA *ptr, PropertyRNA *prop)
void RNA_enum_items_add(EnumPropertyItem **items, int *totitem, const EnumPropertyItem *item)
bNodeTree * ED_node_tree_get(SpaceNode *snode, int level)
void ED_node_tree_start(ARegion *region, SpaceNode *snode, bNodeTree *ntree, ID *id, ID *from)
Definition space_node.cc:78
void ED_node_cursor_location_set(SpaceNode *snode, const float value[2])
void ED_node_tree_pop(ARegion *region, SpaceNode *snode)
void ED_node_tree_path_get(SpaceNode *snode, char *value)
void ED_node_tree_push(ARegion *region, SpaceNode *snode, bNodeTree *ntree, bNode *gnode)
int ED_node_tree_depth(SpaceNode *snode)
void ED_node_set_active_viewer_key(SpaceNode *snode)
int ED_node_tree_path_length(SpaceNode *snode)
void ED_node_cursor_location_get(const SpaceNode *snode, float value[2])
void ED_spacetype_node()
bool(* poll)(const RegionPollParams *params)
void(* free)(ARegion *)
void(* on_poll_success)(const bContext *C, ARegion *region)
bool clip_gizmo_events_by_ui
void(* message_subscribe)(const wmRegionMessageSubscribeParams *params)
void(* cursor)(wmWindow *win, ScrArea *area, ARegion *region)
void(* listener)(const wmRegionListenerParams *params)
void *(* duplicate)(void *poin)
bContextDataCallback context
void(* draw)(const bContext *C, ARegion *region)
void(* layout)(const bContext *C, ARegion *region)
short event_cursor
void(* on_user_resize)(const ARegion *region)
int(* snap_size)(const ARegion *region, int size, int axis)
void(* init)(wmWindowManager *wm, ARegion *region)
ARegionRuntimeHandle * runtime
The meta-data of an asset. By creating and giving this for a data-block (ID.asset_data),...
Definition DNA_ID.h:414
char name[258]
Definition DNA_ID.h:432
short flag
Definition DNA_ID.h:438
unsigned int session_uid
Definition DNA_ID.h:462
void * last
void * first
struct bNodeTree * node_group
struct bNodeTree * compositing_node_group
ListBase spacedata
struct bNodeTree * selected_node_group
char tree_idname[64]
SpaceNode_Runtime * runtime
struct ID * from
ListBase regionbase
char node_tree_sub_type
struct bGPdata * gpd
ListBase treepath
struct bNodeTree * edittree
struct ID * id
SpaceNodeOverlay overlay
struct bNodeTree * nodetree
float minzoom
short keeptot
float max[2]
short keepzoom
float min[2]
float maxzoom
unsigned int value
struct bNodeTree * nodetree
struct bNodeTreePath * next
struct bNodeTreePath * prev
bNodeInstanceKey parent_key
char display_name[64]
float view_center[2]
bNodeTreeRuntimeHandle * runtime
bNodeInstanceKey active_viewer_key
char name[64]
int16_t type_legacy
void * storage
int32_t identifier
float xmax
float xmin
float ymax
float ymin
int ymin
int xmin
const AssetRepresentationHandle * asset
Definition WM_types.hh:1243
eWM_DragDataType type
Definition WM_types.hh:1331
void * poin
Definition WM_types.hh:1332
PointerRNA * ptr
Definition WM_types.hh:1420
wmEventModifierFlag modifier
Definition WM_types.hh:774
int xy[2]
Definition WM_types.hh:761
unsigned int data
Definition WM_types.hh:358
unsigned int action
Definition WM_types.hh:358
unsigned int category
Definition WM_types.hh:358
void * reference
Definition WM_types.hh:360
struct wmEvent * eventstate
i
Definition text_draw.cc:230
uint len
wmDropBox * WM_dropbox_add(ListBase *lb, const char *idname, bool(*poll)(bContext *C, wmDrag *drag, const wmEvent *event), void(*copy)(bContext *C, wmDrag *drag, wmDropBox *drop), void(*cancel)(Main *bmain, wmDrag *drag, wmDropBox *drop), WMDropboxTooltipFunc tooltip)
void WM_drag_free_imported_drag_ID(Main *bmain, wmDrag *drag, wmDropBox *drop)
blender::Span< std::string > WM_drag_get_paths(const wmDrag *drag)
bool WM_drag_is_ID_type(const wmDrag *drag, int idcode)
ID * WM_drag_get_local_ID_or_import_from_asset(const bContext *C, const wmDrag *drag, int idcode)
ListBase * WM_dropboxmap_find(const char *idname, int spaceid, int regionid)
wmDragAsset * WM_drag_get_asset_data(const wmDrag *drag, int idcode)
ID * WM_drag_get_local_ID(const wmDrag *drag, short idcode)
wmEventHandler_Dropbox * WM_event_add_dropbox_handler(ListBase *handlers, ListBase *dropboxes)
wmEventHandler_Keymap * WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
void WM_main_add_notifier(uint type, void *reference)
wmEventHandler_Keymap * WM_event_add_keymap_handler_v2d_mask(ListBase *handlers, wmKeyMap *keymap)
wmGizmoGroupTypeRef * WM_gizmogrouptype_append_and_link(wmGizmoMapType *gzmap_type, void(*wtfunc)(wmGizmoGroupType *))
void WM_gizmomap_tag_refresh(wmGizmoMap *gzmap)
wmGizmoMapType * WM_gizmomaptype_ensure(const wmGizmoMapType_Params *gzmap_params)
wmKeyMap * WM_keymap_ensure(wmKeyConfig *keyconf, const char *idname, int spaceid, int regionid)
Definition wm_keymap.cc:895
bool WM_menutype_add(MenuType *mt)