Blender V5.0
node_add.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2005 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <numeric>
10
12
13#include "MEM_guardedalloc.h"
14
16#include "DNA_node_types.h"
17#include "DNA_texture_types.h"
18
19#include "BLI_easing.h"
20#include "BLI_listbase.h"
21#include "BLI_math_geom.h"
22#include "BLI_string.h"
23#include "BLI_string_utf8.h"
24
25#include "BLT_translation.hh"
26
27#include "BKE_context.hh"
28#include "BKE_image.hh"
29#include "BKE_lib_id.hh"
30#include "BKE_main.hh"
32#include "BKE_node.hh"
34#include "BKE_node_runtime.hh"
36#include "BKE_report.hh"
37#include "BKE_scene.hh"
38#include "BKE_texture.h"
39
41
43
44#include "ED_asset.hh"
46#include "ED_node.hh" /* own include */
47#include "ED_render.hh"
48#include "ED_screen.hh"
49
50#include "RNA_access.hh"
51#include "RNA_define.hh"
52#include "RNA_enum_types.hh"
53#include "RNA_prototypes.hh"
54
55#include "WM_api.hh"
56#include "WM_types.hh"
57
58#include "UI_view2d.hh"
59
60#include "io_utils.hh"
61#include <fmt/format.h>
62
63#include "node_intern.hh" /* own include */
64
66
67/* -------------------------------------------------------------------- */
70
71static void position_node_based_on_mouse(bNode &node, const float2 &location)
72{
73 node.location[0] = location.x - NODE_DY * 1.5f / UI_SCALE_FAC;
74 node.location[1] = location.y + NODE_DY * 0.5f / UI_SCALE_FAC;
75}
76
77bNode *add_node(const bContext &C, const StringRef idname, const float2 &location)
78{
79 SpaceNode &snode = *CTX_wm_space_node(&C);
80 Main &bmain = *CTX_data_main(&C);
81 bNodeTree &node_tree = *snode.edittree;
82
83 node_deselect_all(node_tree);
84
85 bNode *node = bke::node_add_node(&C, node_tree, idname);
86 BLI_assert(node && node->typeinfo);
87
88 position_node_based_on_mouse(*node, location);
89
90 bke::node_set_selected(*node, true);
91 ED_node_set_active(&bmain, &snode, &node_tree, node, nullptr);
92
93 BKE_main_ensure_invariants(bmain, node_tree.id);
94 return node;
95}
96
97bNode *add_static_node(const bContext &C, int type, const float2 &location)
98{
99 SpaceNode &snode = *CTX_wm_space_node(&C);
100 Main &bmain = *CTX_data_main(&C);
101 bNodeTree &node_tree = *snode.edittree;
102
103 node_deselect_all(node_tree);
104
105 bNode *node = bke::node_add_static_node(&C, node_tree, type);
106 BLI_assert(node && node->typeinfo);
107
108 position_node_based_on_mouse(*node, location);
109
110 bke::node_set_selected(*node, true);
111 ED_node_set_active(&bmain, &snode, &node_tree, node, nullptr);
112
113 BKE_main_ensure_invariants(bmain, node_tree.id);
114 return node;
115}
116
121{
122 Main *bmain = CTX_data_main(C);
123 SpaceNode *snode = CTX_wm_space_node(C);
124
126 PropertyRNA *prop;
127
129
130 if (prop) {
131 /* #RNA_property_pointer_set increases the user count, fixed here as the editor is the initial
132 * user. */
133 id_us_min(&node_tree->id);
134
135 if (ptr.owner_id) {
136 BKE_id_move_to_same_lib(*bmain, node_tree->id, *ptr.owner_id);
137 }
138
139 PointerRNA idptr = RNA_id_pointer_create(&node_tree->id);
140 RNA_property_pointer_set(&ptr, prop, idptr, nullptr);
141 RNA_property_update(C, &ptr, prop);
142 }
143 else if (snode) {
144 snode->nodetree = node_tree;
145
146 tree_update(C);
147 }
148}
149
151
152/* -------------------------------------------------------------------- */
155
156std::optional<float2> link_path_intersection(const bNodeLink &link, const Span<float2> path)
157{
158 std::array<float2, NODE_LINK_RESOL + 1> coords;
160
161 for (const int i : path.index_range().drop_back(1)) {
162 for (const int j : IndexRange(NODE_LINK_RESOL)) {
164 if (isect_seg_seg_v2_point(path[i], path[i + 1], coords[j], coords[j + 1], result) > 0) {
165 return result;
166 }
167 }
168 }
169
170 return std::nullopt;
171}
172
174 /* The output socket's owner node. */
176 /* Intersected links connected to the socket and their path intersection locations. */
178};
179
181{
182 const ARegion &region = *CTX_wm_region(C);
183 SpaceNode &snode = *CTX_wm_space_node(C);
184 bNodeTree &ntree = *snode.edittree;
185
186 Vector<float2> path;
187 RNA_BEGIN (op->ptr, itemptr, "path") {
188 float2 loc_region;
189 RNA_float_get_array(&itemptr, "loc", loc_region);
190 float2 loc_view;
191 UI_view2d_region_to_view(&region.v2d, loc_region.x, loc_region.y, &loc_view.x, &loc_view.y);
192 path.append(loc_view);
193 if (path.size() >= 256) {
194 break;
195 }
196 }
197 RNA_END;
198
199 if (path.is_empty()) {
201 }
202
203 node_deselect_all(ntree);
204
205 ntree.ensure_topology_cache();
206 const Vector<bNode *> frame_nodes = ntree.nodes_by_type("NodeFrame");
207
209
210 /* All link "cuts" that start at a particular output socket. Deduplicating new reroutes per
211 * output socket is useful because it allows reusing reroutes for connected intersections.
212 * Further deduplication using the second map means we only have one cut per link. */
214
215 int intersection_count = 0;
216
217 LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
218
219 if (node_link_is_hidden_or_dimmed(region.v2d, *link)) {
220 continue;
221 }
222 const std::optional<float2> cut = link_path_intersection(*link, path);
223 if (!cut) {
224 continue;
225 }
226 RerouteCutsForSocket &from_cuts = cuts_per_socket.lookup_or_add_default(link->fromsock);
227 from_cuts.from_node = link->fromnode;
228 from_cuts.links.add(link, *cut);
229 intersection_count++;
230 }
231
232 for (const auto item : cuts_per_socket.items()) {
233 const Map<bNodeLink *, float2> &cuts = item.value.links;
234
235 bNode *reroute = bke::node_add_static_node(C, ntree, NODE_REROUTE);
236
237 if (intersection_count == 1) {
238 bke::node_set_active(ntree, *reroute);
239 }
240
241 bke::node_add_link(ntree,
242 *item.value.from_node,
243 *item.key,
244 *reroute,
245 *static_cast<bNodeSocket *>(reroute->inputs.first));
246
247 /* Reconnect links from the original output socket to the new reroute. */
248 for (bNodeLink *link : cuts.keys()) {
249 link->fromnode = reroute;
250 link->fromsock = static_cast<bNodeSocket *>(reroute->outputs.first);
252 }
253
254 /* Place the new reroute at the average location of all connected cuts. */
255 const float2 insert_point = std::accumulate(
256 cuts.values().begin(), cuts.values().end(), float2(0)) /
257 cuts.size();
258 reroute->location[0] = insert_point.x / UI_SCALE_FAC;
259 reroute->location[1] = insert_point.y / UI_SCALE_FAC;
260
261 /* Attach the reroute node to frame nodes behind it. */
262 for (const int i : frame_nodes.index_range()) {
263 bNode *frame_node = frame_nodes.last(i);
264 if (BLI_rctf_isect_pt_v(&frame_node->runtime->draw_bounds, insert_point)) {
265 bke::node_attach_node(ntree, *reroute, *frame_node);
266 break;
267 }
268 }
269 }
270
272 return OPERATOR_FINISHED;
273}
274
276{
277 ot->name = "Add Reroute";
278 ot->idname = "NODE_OT_add_reroute";
279 ot->description = "Add a reroute node";
280
281 ot->invoke = WM_gesture_lines_invoke;
282 ot->modal = WM_gesture_lines_modal;
283 ot->exec = add_reroute_exec;
284 ot->cancel = WM_gesture_lines_cancel;
285
287
288 /* flags */
290
291 /* properties */
292 PropertyRNA *prop;
293 prop = RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
295 /* internal */
296 RNA_def_int(ot->srna, "cursor", WM_CURSOR_CROSS, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
297}
298
300
301/* -------------------------------------------------------------------- */
304
305static bool node_group_add_poll(const bNodeTree &node_tree,
306 const bNodeTree &node_group,
307 ReportList &reports)
308{
309 if (node_group.type != node_tree.type) {
310 return false;
311 }
312
313 const char *disabled_hint = nullptr;
314 if (!bke::node_group_poll(&node_tree, &node_group, &disabled_hint)) {
315 if (disabled_hint) {
316 BKE_reportf(&reports,
317 RPT_ERROR,
318 "Cannot add node group '%s' to '%s':\n %s",
319 node_group.id.name + 2,
320 node_tree.id.name + 2,
321 disabled_hint);
322 }
323 else {
324 BKE_reportf(&reports,
325 RPT_ERROR,
326 "Cannot add node group '%s' to '%s'",
327 node_group.id.name + 2,
328 node_tree.id.name + 2);
329 }
330
331 return false;
332 }
333
334 return true;
335}
336
338{
339 Main *bmain = CTX_data_main(C);
340 SpaceNode *snode = CTX_wm_space_node(C);
341 bNodeTree *ntree = snode->edittree;
342
343 bNodeTree *node_group = reinterpret_cast<bNodeTree *>(
345 if (!node_group) {
346 return OPERATOR_CANCELLED;
347 }
348 if (!node_group_add_poll(*ntree, *node_group, *op->reports)) {
349 return OPERATOR_CANCELLED;
350 }
351
353
354 const StringRef node_idname = node_group_idname(C);
355 if (node_idname[0] == '\0') {
356 BKE_report(op->reports, RPT_WARNING, "Could not determine type of group node");
357 return OPERATOR_CANCELLED;
358 }
359
360 bNode *group_node = add_node(*C, node_idname, snode->runtime->cursor);
361 if (!group_node) {
362 BKE_report(op->reports, RPT_WARNING, "Could not add node group");
363 return OPERATOR_CANCELLED;
364 }
365 if (!RNA_boolean_get(op->ptr, "show_datablock_in_node")) {
366 /* By default, don't show the data-block selector since it's not usually necessary for assets.
367 */
368 group_node->flag &= ~NODE_OPTIONS;
369 }
370 group_node->width = node_group->default_group_node_width;
371
372 group_node->id = &node_group->id;
373 id_us_plus(group_node->id);
375
376 bke::node_set_active(*ntree, *group_node);
380 return OPERATOR_FINISHED;
381}
382
384{
386 return false;
387 }
388 const SpaceNode *snode = CTX_wm_space_node(C);
389 if (snode->edittree->type == NTREE_CUSTOM) {
391 C, "Adding node groups isn't supported for custom (Python defined) node trees");
392 return false;
393 }
394 return true;
395}
396
398{
400 return false;
401 }
402 const SpaceNode *snode = CTX_wm_space_node(C);
403 if (snode->edittree->type == NTREE_CUSTOM) {
405 C, "Adding node groups isn't supported for custom (Python defined) node trees");
406 return false;
407 }
408 Vector<PointerRNA> selected_nodes;
409 selected_nodes = CTX_data_collection_get(C, "selected_nodes");
410
411 if (selected_nodes.size() <= 0) {
412 CTX_wm_operator_poll_msg_set(C, "No nodes selected.");
413 return false;
414 }
415 return true;
416}
417
419{
420 ARegion *region = CTX_wm_region(C);
421 SpaceNode *snode = CTX_wm_space_node(C);
422
423 /* Convert mouse coordinates to v2d space. */
425 event->mval[0],
426 event->mval[1],
427 &snode->runtime->cursor[0],
428 &snode->runtime->cursor[1]);
429
430 snode->runtime->cursor[0] /= UI_SCALE_FAC;
431 snode->runtime->cursor[1] /= UI_SCALE_FAC;
432
433 return node_add_group_exec(C, op);
434}
435
437{
438 /* identifiers */
439 ot->name = "Add Node Group";
440 ot->description = "Add an existing node group to the current node editor";
441 ot->idname = "NODE_OT_add_group";
442
443 /* callbacks */
444 ot->exec = node_add_group_exec;
445 ot->invoke = node_add_group_invoke;
446 ot->poll = node_add_group_poll;
447
448 /* flags */
450
452
454 ot->srna, "show_datablock_in_node", true, "Show the data-block selector in the node", "");
456}
457
459
460/* -------------------------------------------------------------------- */
463
464static bool add_node_group_asset(const bContext &C,
466 ReportList &reports)
467{
468 Main &bmain = *CTX_data_main(&C);
469 SpaceNode &snode = *CTX_wm_space_node(&C);
470 bNodeTree &edit_tree = *snode.edittree;
471
472 bNodeTree *node_group = reinterpret_cast<bNodeTree *>(
474 if (!node_group) {
475 return false;
476 }
477 if (!node_group_add_poll(edit_tree, *node_group, reports)) {
478 /* Remove the node group if it was newly appended but can't be added to the tree. */
479 id_us_plus(&node_group->id);
480 BKE_id_free_us(&bmain, node_group);
481 return false;
482 }
483
485
486 bNode *group_node = add_node(
487 C, bke::node_tree_type_find(node_group->idname)->group_idname, snode.runtime->cursor);
488 if (!group_node) {
489 BKE_report(&reports, RPT_WARNING, "Could not add node group");
490 return false;
491 }
492 STRNCPY_UTF8(group_node->name, BKE_id_name(node_group->id));
493 bke::node_unique_name(*snode.edittree, *group_node);
494
495 /* By default, don't show the data-block selector since it's not usually necessary for assets. */
496 group_node->flag &= ~NODE_OPTIONS;
497 group_node->width = node_group->default_group_node_width;
498
499 group_node->id = &node_group->id;
500 id_us_plus(group_node->id);
501 BKE_ntree_update_tag_node_property(&edit_tree, group_node);
502
503 bke::node_set_active(edit_tree, *group_node);
507
508 return true;
509}
510
512 wmOperator *op,
513 const wmEvent *event)
514{
515 ARegion &region = *CTX_wm_region(C);
516 SpaceNode &snode = *CTX_wm_space_node(C);
517
520 if (!asset) {
521 return OPERATOR_CANCELLED;
522 }
523
524 /* Convert mouse coordinates to v2d space. */
526 event->mval[0],
527 event->mval[1],
528 &snode.runtime->cursor[0],
529 &snode.runtime->cursor[1]);
530
531 snode.runtime->cursor /= UI_SCALE_FAC;
532
533 if (!add_node_group_asset(*C, *asset, *op->reports)) {
534 return OPERATOR_CANCELLED;
535 }
536
537 wmOperatorType *ot = WM_operatortype_find("NODE_OT_translate_attach_remove_on_cancel", true);
538 BLI_assert(ot);
543
544 return OPERATOR_FINISHED;
545}
546
548 wmOperator *op,
549 const wmEvent *event)
550{
551 ARegion &region = *CTX_wm_region(C);
552 Main &bmain = *CTX_data_main(C);
553 SpaceNode &snode = *CTX_wm_space_node(C);
554 bNodeTree &ntree = *snode.edittree;
555
558 if (!asset) {
559 return OPERATOR_CANCELLED;
560 }
561 bNodeTree *node_group = reinterpret_cast<bNodeTree *>(
563
564 /* Convert mouse coordinates to v2d space. */
566 event->mval[0],
567 event->mval[1],
568 &snode.runtime->cursor[0],
569 &snode.runtime->cursor[1]);
570
571 snode.runtime->cursor /= UI_SCALE_FAC;
572
573 const StringRef node_idname = node_group_idname(C);
574 if (node_idname[0] == '\0') {
575 BKE_report(op->reports, RPT_WARNING, "Could not determine type of group node");
576 return OPERATOR_CANCELLED;
577 }
578 wmOperatorType *ot = WM_operatortype_find("NODE_OT_swap_node", true);
579 BLI_assert(ot);
581 PointerRNA itemptr;
583 RNA_string_set(&ptr, "type", node_idname.data());
584
585 /* Assign node group via operator.settings. This needs to be done here so that NODE_OT_swap_node
586 * can preserve matching links */
587 /* Assigning it in the for-loop along with the other node group properties causes the links to
588 * not be preserved*/
589 RNA_collection_add(&ptr, "settings", &itemptr);
590 RNA_string_set(&itemptr, "name", "node_tree");
591
592 std::string setting_value = "bpy.data.node_groups[\"" +
593 std::string(BKE_id_name(node_group->id)) + "\"]";
594 RNA_string_set(&itemptr, "value", setting_value.c_str());
595
598
599 for (bNode *group_node : get_selected_nodes(ntree)) {
600 STRNCPY_UTF8(group_node->name, BKE_id_name(node_group->id));
601 bke::node_unique_name(*snode.edittree, *group_node);
602
603 /* By default, don't show the data-block selector since it's not usually necessary for assets.
604 */
605 group_node->flag &= ~NODE_OPTIONS;
606 group_node->width = node_group->default_group_node_width;
607
608 id_us_plus(group_node->id);
609 BKE_ntree_update_tag_node_property(&ntree, group_node);
610 }
611
615
616 return OPERATOR_FINISHED;
617}
618
620 wmOperatorType * /*ot*/,
622{
625 if (!asset) {
626 return "";
627 }
628 const AssetMetaData &asset_data = asset->get_metadata();
629 if (!asset_data.description) {
630 return "";
631 }
632 return TIP_(asset_data.description);
633}
634
636{
637 ot->name = "Add Node Group Asset";
638 ot->description = "Add a node group asset to the active node tree";
639 ot->idname = "NODE_OT_add_group_asset";
640
642 ot->poll = node_add_group_poll;
643 ot->get_description = node_add_group_asset_get_description;
644
646
648}
649
651{
652 ot->name = "Swap Node Group Asset";
653 ot->description = "Swap selected nodes with the specified node group asset";
654 ot->idname = "NODE_OT_swap_group_asset";
655
657 ot->poll = node_swap_group_poll;
658 ot->get_description = node_add_group_asset_get_description;
659
661
663}
664
666
667/* -------------------------------------------------------------------- */
670
672{
673 Main *bmain = CTX_data_main(C);
674 SpaceNode *snode = CTX_wm_space_node(C);
675 bNodeTree *ntree = snode->edittree;
676
677 Object *object = reinterpret_cast<Object *>(
679
680 if (!object) {
681 return OPERATOR_CANCELLED;
682 }
683
685
686 bNode *object_node = add_static_node(*C, GEO_NODE_OBJECT_INFO, snode->runtime->cursor);
687 if (!object_node) {
688 BKE_report(op->reports, RPT_WARNING, "Could not add node object");
689 return OPERATOR_CANCELLED;
690 }
691
692 bNodeSocket *sock = bke::node_find_socket(*object_node, SOCK_IN, "Object");
693 if (!sock) {
695 return OPERATOR_CANCELLED;
696 }
697
699 socket_data->value = object;
700 id_us_plus(&object->id);
702
703 bke::node_set_active(*ntree, *object_node);
704 BKE_main_ensure_invariants(*bmain, ntree->id);
706
707 return OPERATOR_FINISHED;
708}
709
711{
712 ARegion *region = CTX_wm_region(C);
713 SpaceNode *snode = CTX_wm_space_node(C);
714
715 /* Convert mouse coordinates to v2d space. */
717 event->mval[0],
718 event->mval[1],
719 &snode->runtime->cursor[0],
720 &snode->runtime->cursor[1]);
721
722 snode->runtime->cursor[0] /= UI_SCALE_FAC;
723 snode->runtime->cursor[1] /= UI_SCALE_FAC;
724
725 return node_add_object_exec(C, op);
726}
727
729{
730 const SpaceNode *snode = CTX_wm_space_node(C);
732}
733
735{
736 /* identifiers */
737 ot->name = "Add Node Object";
738 ot->description = "Add an object info node to the current node editor";
739 ot->idname = "NODE_OT_add_object";
740
741 /* callbacks */
742 ot->exec = node_add_object_exec;
743 ot->invoke = node_add_object_invoke;
744 ot->poll = node_add_object_poll;
745
746 /* flags */
748
750}
751
753
754/* -------------------------------------------------------------------- */
757
759{
760 Main *bmain = CTX_data_main(C);
761 SpaceNode &snode = *CTX_wm_space_node(C);
762 bNodeTree &ntree = *snode.edittree;
763
764 Collection *collection = reinterpret_cast<Collection *>(
766
767 if (!collection) {
768 return OPERATOR_CANCELLED;
769 }
770
772
773 bNode *collection_node = add_static_node(*C, GEO_NODE_COLLECTION_INFO, snode.runtime->cursor);
774 if (!collection_node) {
775 BKE_report(op->reports, RPT_WARNING, "Could not add node collection");
776 return OPERATOR_CANCELLED;
777 }
778
779 bNodeSocket *sock = bke::node_find_socket(*collection_node, SOCK_IN, "Collection");
780 if (!sock) {
781 BKE_report(op->reports, RPT_WARNING, "Could not find node collection socket");
782 return OPERATOR_CANCELLED;
783 }
784
786 socket_data->value = collection;
787 id_us_plus(&collection->id);
789
790 bke::node_set_active(ntree, *collection_node);
791 BKE_main_ensure_invariants(*bmain, ntree.id);
793
794 return OPERATOR_FINISHED;
795}
796
798 wmOperator *op,
799 const wmEvent *event)
800{
801 ARegion *region = CTX_wm_region(C);
802 SpaceNode *snode = CTX_wm_space_node(C);
803
804 /* Convert mouse coordinates to v2d space. */
806 event->mval[0],
807 event->mval[1],
808 &snode->runtime->cursor[0],
809 &snode->runtime->cursor[1]);
810
811 snode->runtime->cursor[0] /= UI_SCALE_FAC;
812 snode->runtime->cursor[1] /= UI_SCALE_FAC;
813
814 return node_add_collection_exec(C, op);
815}
816
818{
819 const SpaceNode *snode = CTX_wm_space_node(C);
821}
822
824{
825 /* identifiers */
826 ot->name = "Add Node Collection";
827 ot->description = "Add a collection info node to the current node editor";
828 ot->idname = "NODE_OT_add_collection";
829
830 /* callbacks */
834
835 /* flags */
837
839}
840
842
843/* -------------------------------------------------------------------- */
846
848{
849 const SpaceNode *snode = CTX_wm_space_node(C);
850 if (!snode) {
851 return false;
852 }
853
854 /* Note: Validity of snode->nodetree is checked later for better error reporting. */
855 return STR_ELEM(snode->tree_idname,
856 "ShaderNodeTree",
857 "CompositorNodeTree",
858 "TextureNodeTree",
859 "GeometryNodeTree");
860}
861
867
869{
871
872 if (event->type != TIMER || data == nullptr || data->anim_timer != event->customdata) {
874 }
875
876 const float node_stack_anim_duration = 0.25f;
877 const float duration = float(data->anim_timer->time_duration);
878 const float prev_duration = duration - float(data->anim_timer->time_delta);
879 const float clamped_duration = math::min(duration, node_stack_anim_duration);
880 const float delta_factor =
881 BLI_easing_cubic_ease_in_out(clamped_duration, 0.0f, 1.0f, node_stack_anim_duration) -
882 BLI_easing_cubic_ease_in_out(prev_duration, 0.0f, 1.0f, node_stack_anim_duration);
883
884 bool redraw = false;
885 /* Each node is pushed by all previous nodes in the stack. */
886 float stack_offset = 0.0f;
887
888 for (bNode *node : data->nodes) {
889 node->location[1] -= stack_offset;
890 stack_offset += (node->runtime->draw_bounds.ymax - node->runtime->draw_bounds.ymin) *
891 delta_factor;
892 redraw = true;
893 }
894
895 if (redraw) {
897 }
898
899 /* End stack animation. */
900 if (duration > node_stack_anim_duration) {
901 WM_event_timer_remove(CTX_wm_manager(C), nullptr, data->anim_timer);
902 MEM_delete(data);
903 op->customdata = nullptr;
905 }
906
908}
909
911{
912 Main *bmain = CTX_data_main(C);
913 SpaceNode &snode = *CTX_wm_space_node(C);
914 int type = 0;
915 switch (snode.nodetree->type) {
916 case NTREE_SHADER:
917 type = SH_NODE_TEX_IMAGE;
918 break;
919 case NTREE_TEXTURE:
920 type = TEX_NODE_IMAGE;
921 break;
922 case NTREE_COMPOSIT:
923 type = CMP_NODE_IMAGE;
924 break;
925 case NTREE_GEOMETRY:
927 break;
928 default:
929 return OPERATOR_CANCELLED;
930 }
931 Vector<Image *> images;
932 /* Load all paths as ID Images. */
934 for (const std::string &path : paths) {
935 RNA_string_set(op->ptr, "filepath", path.c_str());
936 Image *image = (Image *)WM_operator_drop_load_path(C, op, ID_IM);
937 if (!image) {
938 BKE_report(op->reports, RPT_WARNING, fmt::format("Could not load {}", path).c_str());
939 continue;
940 }
941 images.append(image);
942 /* When adding new image file via drag-drop we need to load #ImBuf in order
943 * to get proper image source. */
944 BKE_image_signal(bmain, image, nullptr, IMA_SIGNAL_RELOAD);
946 }
947
948 /* If not path is provided, try to get a ID Image from operator. */
949 if (paths.is_empty()) {
950 Image *image = (Image *)WM_operator_drop_load_path(C, op, ID_IM);
951 if (image) {
952 images.append(image);
953 }
954 }
955
956 bNodeTree &node_tree = *snode.edittree;
957 float2 position = snode.runtime->cursor;
959 /* Add a node for each image. */
960 for (Image *image : images) {
961 bNode *node = add_static_node(*C, type, position);
962 if (!node) {
963 BKE_report(op->reports, RPT_WARNING, "Could not add an image node");
964 continue;
965 }
966 if (type == GEO_NODE_IMAGE_TEXTURE) {
967 bNodeSocket *image_socket = (bNodeSocket *)node->inputs.first;
968 bNodeSocketValueImage *socket_value = (bNodeSocketValueImage *)image_socket->default_value;
969 socket_value->value = image;
970 BKE_ntree_update_tag_socket_property(&node_tree, image_socket);
971 }
972 else {
973 node->id = (ID *)image;
975 }
976 BKE_ntree_update_tag_node_property(&node_tree, node);
977 nodes.append(node);
978 /* Initial offset between nodes. */
979 position[1] -= 20.0f;
980 }
981
982 if (nodes.is_empty()) {
983 return OPERATOR_CANCELLED;
984 }
985
986 /* Set new nodes as selected. */
987 node_deselect_all(node_tree);
988 for (bNode *node : nodes) {
989 bke::node_set_selected(*node, true);
990 }
991 ED_node_set_active(bmain, &snode, &node_tree, nodes[0], nullptr);
992
994
995 BKE_main_ensure_invariants(*bmain, snode.edittree->id);
997
998 if (nodes.size() == 1) {
999 return OPERATOR_FINISHED;
1000 }
1001
1002 /* Start the stack animation, so each node is placed on top of each other. */
1003 NodeStackAnimationData *data = MEM_new<NodeStackAnimationData>(__func__);
1004 data->nodes = std::move(nodes);
1005 data->anim_timer = WM_event_timer_add(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.02);
1006 op->customdata = data;
1008
1010}
1011
1013{
1014 ARegion *region = CTX_wm_region(C);
1015 SpaceNode *snode = CTX_wm_space_node(C);
1016
1018 BKE_report(op->reports,
1019 RPT_ERROR,
1020 "Could not add image. A node tree has not been created or assigned");
1021 return OPERATOR_CANCELLED;
1022 }
1023
1024 /* Convert mouse coordinates to `v2d` space. */
1026 event->mval[0],
1027 event->mval[1],
1028 &snode->runtime->cursor[0],
1029 &snode->runtime->cursor[1]);
1030
1031 snode->runtime->cursor[0] /= UI_SCALE_FAC;
1032 snode->runtime->cursor[1] /= UI_SCALE_FAC;
1033
1035 RNA_struct_property_is_set(op->ptr, "filepath"))
1036 {
1037 return node_add_image_exec(C, op);
1038 }
1039 return WM_operator_filesel(C, op, event);
1040}
1041
1043{
1044 /* identifiers */
1045 ot->name = "Add Image as Node";
1046 ot->description = "Add a image/movie file as node to the current node editor";
1047 ot->idname = "NODE_OT_add_image";
1048
1049 /* callbacks */
1050 ot->exec = node_add_image_exec;
1051 ot->modal = node_add_nodes_modal;
1052 ot->invoke = node_add_image_invoke;
1053 ot->poll = node_add_image_poll;
1054
1055 /* flags */
1056 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1057
1067}
1068
1070
1071/* -------------------------------------------------------------------- */
1074
1076{
1077 SpaceNode *snode = CTX_wm_space_node(C);
1078
1080}
1081
1083{
1084 Main *bmain = CTX_data_main(C);
1085 SpaceNode &snode = *CTX_wm_space_node(C);
1086
1088 if (!mask) {
1089 return OPERATOR_CANCELLED;
1090 }
1091
1093
1095
1096 if (!node) {
1097 BKE_report(op->reports, RPT_WARNING, "Could not add a mask node");
1098 return OPERATOR_CANCELLED;
1099 }
1100
1101 node->id = mask;
1103
1104 BKE_main_ensure_invariants(*bmain, snode.edittree->id);
1106
1107 return OPERATOR_FINISHED;
1108}
1109
1111{
1112 /* identifiers */
1113 ot->name = "Add Mask Node";
1114 ot->description = "Add a mask node to the current node editor";
1115 ot->idname = "NODE_OT_add_mask";
1116
1117 /* callbacks */
1118 ot->exec = node_add_mask_exec;
1119 ot->poll = node_add_mask_poll;
1120
1121 /* flags */
1123
1125}
1126
1128
1129/* -------------------------------------------------------------------- */
1132
1134{
1135 Main *bmain = CTX_data_main(C);
1136 SpaceNode *snode = CTX_wm_space_node(C);
1137 bNodeTree *ntree = snode->edittree;
1138
1139 Material *material = reinterpret_cast<Material *>(
1141
1142 if (!material) {
1143 return OPERATOR_CANCELLED;
1144 }
1145
1147
1148 bNode *material_node = add_static_node(*C, GEO_NODE_INPUT_MATERIAL, snode->runtime->cursor);
1149 if (!material_node) {
1150 BKE_report(op->reports, RPT_WARNING, "Could not add material");
1151 return OPERATOR_CANCELLED;
1152 }
1153
1154 material_node->id = &material->id;
1155 id_us_plus(&material->id);
1156
1157 BKE_main_ensure_invariants(*bmain, ntree->id);
1159
1160 return OPERATOR_FINISHED;
1161}
1162
1164{
1165 ARegion *region = CTX_wm_region(C);
1166 SpaceNode *snode = CTX_wm_space_node(C);
1167
1168 /* Convert mouse coordinates to v2d space. */
1170 event->mval[0],
1171 event->mval[1],
1172 &snode->runtime->cursor[0],
1173 &snode->runtime->cursor[1]);
1174
1175 snode->runtime->cursor[0] /= UI_SCALE_FAC;
1176 snode->runtime->cursor[1] /= UI_SCALE_FAC;
1177
1178 return node_add_material_exec(C, op);
1179}
1180
1182{
1183 const SpaceNode *snode = CTX_wm_space_node(C);
1185}
1186
1188{
1189 /* identifiers */
1190 ot->name = "Add Material";
1191 ot->description = "Add a material node to the current node editor";
1192 ot->idname = "NODE_OT_add_material";
1193
1194 /* callbacks */
1195 ot->exec = node_add_material_exec;
1196 ot->invoke = node_add_material_invoke;
1197 ot->poll = node_add_material_poll;
1198
1199 /* flags */
1201
1203}
1204
1206
1207/* -------------------------------------------------------------------- */
1210
1212{
1213 Main *bmain = CTX_data_main(C);
1214 SpaceNode *snode = CTX_wm_space_node(C);
1215 bNodeTree *ntree = snode->edittree;
1216
1218
1219 Vector<bNode *> new_nodes;
1220 for (const StringRefNull path : paths) {
1221 bNode *node = nullptr;
1222 if (path.endswith(".csv")) {
1223 node = add_node(*C, "GeometryNodeImportCSV", snode->runtime->cursor);
1224 }
1225 else if (path.endswith(".obj")) {
1226 node = add_node(*C, "GeometryNodeImportOBJ", snode->runtime->cursor);
1227 }
1228 else if (path.endswith(".ply")) {
1229 node = add_node(*C, "GeometryNodeImportPLY", snode->runtime->cursor);
1230 }
1231 else if (path.endswith(".stl")) {
1232 node = add_node(*C, "GeometryNodeImportSTL", snode->runtime->cursor);
1233 }
1234 else if (path.endswith(".txt")) {
1235 node = add_node(*C, "GeometryNodeImportText", snode->runtime->cursor);
1236 }
1237 else if (path.endswith(".vdb")) {
1238 node = add_node(*C, "GeometryNodeImportVDB", snode->runtime->cursor);
1239 }
1240
1241 if (node) {
1242 bNodeSocket &path_socket = *node->input_by_identifier("Path");
1243 BLI_assert(path_socket.type == SOCK_STRING);
1244 auto *socket_data = static_cast<bNodeSocketValueString *>(path_socket.default_value);
1245 STRNCPY(socket_data->value, path.c_str());
1246 new_nodes.append(node);
1247 }
1248 }
1249
1250 if (new_nodes.is_empty()) {
1251 return OPERATOR_CANCELLED;
1252 }
1253
1254 node_deselect_all(*ntree);
1255
1256 for (const int i : new_nodes.index_range()) {
1257 bNode *node = new_nodes[i];
1258 node->flag |= NODE_SELECT;
1259 }
1260 bke::node_set_active(*ntree, *new_nodes[0]);
1261
1262 NodeStackAnimationData *data = MEM_new<NodeStackAnimationData>(__func__);
1263 data->nodes = std::move(new_nodes);
1264 data->anim_timer = WM_event_timer_add(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.02);
1265 op->customdata = data;
1267
1268 BKE_main_ensure_invariants(*bmain, ntree->id);
1269
1271}
1272
1274 wmOperator *op,
1275 const wmEvent *event)
1276{
1277 ARegion *region = CTX_wm_region(C);
1278 SpaceNode *snode = CTX_wm_space_node(C);
1279
1280 /* Convert mouse coordinates to v2d space. */
1282 event->mval[0],
1283 event->mval[1],
1284 &snode->runtime->cursor[0],
1285 &snode->runtime->cursor[1]);
1286
1287 snode->runtime->cursor[0] /= UI_SCALE_FAC;
1288 snode->runtime->cursor[1] /= UI_SCALE_FAC;
1289
1290 return node_add_import_node_exec(C, op);
1291}
1292
1294{
1295 const SpaceNode *snode = CTX_wm_space_node(C);
1297}
1298
1300{
1301 ot->name = "Add Import Node";
1302 ot->description = "Add an import node to the node tree";
1303 ot->idname = "NODE_OT_add_import_node";
1304
1308 ot->modal = node_add_nodes_modal;
1309
1311
1312 PropertyRNA *prop;
1313
1315 ot->srna, "directory", nullptr, FILE_MAX, "Directory", "Directory of the file");
1317
1318 prop = RNA_def_collection_runtime(ot->srna, "files", &RNA_OperatorFileListElement, "Files", "");
1320}
1321
1323
1324/* -------------------------------------------------------------------- */
1327
1329{
1330 SpaceNode *snode = CTX_wm_space_node(C);
1331 bNodeTree *ntree = snode->edittree;
1332
1333 bool single_socket = false;
1334 char socket_identifier[int(sizeof(bNodeSocket::idname))];
1335 bool single_panel = false;
1336 int panel_identifier = 0;
1337 if (RNA_struct_property_is_set(op->ptr, "socket_identifier")) {
1338 single_socket = true;
1339 RNA_string_get(op->ptr, "socket_identifier", socket_identifier);
1340 }
1341 if (RNA_struct_property_is_set(op->ptr, "panel_identifier")) {
1342 single_panel = true;
1343 panel_identifier = RNA_int_get(op->ptr, "panel_identifier");
1344 }
1345 if (single_socket && single_panel) {
1346 BKE_report(op->reports, RPT_ERROR, "Cannot set both socket and panel identifier");
1347 return OPERATOR_CANCELLED;
1348 }
1349
1350 bNodeTreeInterfacePanel *interface_panel = nullptr;
1351
1352 if (single_socket) {
1353 /* Ensure the requested socket exists in the node interface. */
1354 bNodeTreeInterfaceSocket *interface_socket = nullptr;
1355 for (bNodeTreeInterfaceSocket *tsocket : ntree->interface_inputs()) {
1356 if (STREQ(socket_identifier, tsocket->identifier)) {
1357 interface_socket = tsocket;
1358 break;
1359 }
1360 }
1361 if (!interface_socket) {
1362 BKE_report(
1363 op->reports,
1364 RPT_ERROR,
1365 fmt::format("Invalid socket_identifier: Socket \"%s\" not found", socket_identifier)
1366 .c_str());
1367 return OPERATOR_CANCELLED;
1368 }
1369 }
1370 if (single_panel) {
1371 /* Ensure the requested panel exists in the node interface. */
1372 for (bNodeTreeInterfaceItem *item : ntree->interface_items()) {
1374 item);
1375 if (tpanel && tpanel->identifier == panel_identifier) {
1376 interface_panel = tpanel;
1377 break;
1378 }
1379 }
1380
1381 if (!interface_panel) {
1382 BKE_report(op->reports, RPT_ERROR, "Invalid panel identifier");
1383 return OPERATOR_CANCELLED;
1384 }
1385 }
1386
1388
1389 bNode *group_input_node = add_node(*C, "NodeGroupInput", snode->runtime->cursor);
1390
1391 if (single_socket) {
1392 /* Hide all other sockets in the new node, to only display the selected one. */
1393 LISTBASE_FOREACH (bNodeSocket *, socket, &group_input_node->outputs) {
1394 if (!STREQ(socket->identifier, socket_identifier)) {
1395 socket->flag |= SOCK_HIDDEN;
1396 }
1397 }
1398 }
1399 if (single_panel) {
1400 /* Initially hide all sockets. */
1401 LISTBASE_FOREACH (bNodeSocket *, socket, &group_input_node->outputs) {
1402 socket->flag |= SOCK_HIDDEN;
1403 }
1404 /* Show only sockets contained in the dragged panel. */
1405 for (bNodeTreeInterfaceSocket *iface_socket : ntree->interface_inputs()) {
1406 if (interface_panel->contains_recursive(iface_socket->item)) {
1408 *group_input_node, SOCK_OUT, iface_socket->identifier);
1409 BLI_assert(socket);
1410 socket->flag &= ~SOCK_HIDDEN;
1411 }
1412 }
1413 }
1414
1415 return OPERATOR_FINISHED;
1416}
1417
1419 wmOperator *op,
1420 const wmEvent *event)
1421{
1422 ARegion *region = CTX_wm_region(C);
1423 SpaceNode *snode = CTX_wm_space_node(C);
1424
1425 /* Convert mouse coordinates to v2d space. */
1427 event->mval[0],
1428 event->mval[1],
1429 &snode->runtime->cursor[0],
1430 &snode->runtime->cursor[1]);
1431
1432 snode->runtime->cursor[0] /= UI_SCALE_FAC;
1433 snode->runtime->cursor[1] /= UI_SCALE_FAC;
1434
1436}
1437
1439{
1441 return false;
1442 }
1443
1444 const SpaceNode *snode = CTX_wm_space_node(C);
1445 bNodeTree *ntree = snode->edittree;
1446
1447 bNodeTreeInterface interface = ntree->tree_interface;
1448 bNodeTreeInterfaceItem *active_item = interface.active_item();
1449
1450 if (auto *socket = bke::node_interface::get_item_as<bNodeTreeInterfaceSocket>(active_item)) {
1451 if (socket->flag & NODE_INTERFACE_SOCKET_OUTPUT) {
1452 CTX_wm_operator_poll_msg_set(C, "Cannot drag an output socket");
1453 return false;
1454 }
1455 return true;
1456 }
1457
1458 if (auto *panel = bke::node_interface::get_item_as<bNodeTreeInterfacePanel>(active_item)) {
1459 bool has_inputs = false;
1460 for (bNodeTreeInterfaceSocket *socket : ntree->interface_inputs()) {
1461 if (panel->contains_recursive(socket->item)) {
1462 has_inputs = true;
1463 break;
1464 }
1465 }
1466
1467 if (!has_inputs) {
1468 CTX_wm_operator_poll_msg_set(C, "Cannot drag panel with no inputs");
1469 return false;
1470 }
1471 return true;
1472 }
1473 return false;
1474}
1475
1477{
1478 ot->name = "Add Group Input Node";
1479 ot->description = "Add a Group Input node with selected sockets to the current node editor";
1480 ot->idname = "NODE_OT_add_group_input_node";
1481
1485
1487
1488 PropertyRNA *prop = RNA_def_string(ot->srna,
1489 "socket_identifier",
1490 nullptr,
1491 int(sizeof(bNodeSocket::idname)),
1492 "Socket Identifier",
1493 "Socket to include in the added group input/output node");
1495 prop = RNA_def_int(ot->srna,
1496 "panel_identifier",
1497 0,
1498 INT_MIN,
1499 INT_MAX,
1500 "Panel Identifier",
1501 "Panel from which to add sockets to the added group input/output node",
1502 INT_MIN,
1503 INT_MAX);
1505}
1506
1508
1509/* -------------------------------------------------------------------- */
1512
1514{
1515 Main *bmain = CTX_data_main(C);
1516 SpaceNode *snode = CTX_wm_space_node(C);
1517 bNodeTree *ntree = snode->edittree;
1518
1519 float color[4];
1520 RNA_float_get_array(op->ptr, "color", color);
1521 const bool gamma = RNA_boolean_get(op->ptr, "gamma");
1522 const bool has_alpha = RNA_boolean_get(op->ptr, "has_alpha");
1523
1524 if (!has_alpha) {
1525 color[3] = 1.0f;
1526 }
1527
1528 if (gamma) {
1530 }
1531
1532 bNode *color_node;
1533
1534 switch (snode->nodetree->type) {
1535 case NTREE_SHADER:
1536 color_node = add_node(*C, "ShaderNodeRGB", snode->runtime->cursor);
1537 break;
1538 case NTREE_COMPOSIT:
1539 color_node = add_node(*C, "CompositorNodeRGB", snode->runtime->cursor);
1540 break;
1541 case NTREE_GEOMETRY:
1542 color_node = add_node(*C, "FunctionNodeInputColor", snode->runtime->cursor);
1543 break;
1544 default:
1545 return OPERATOR_CANCELLED;
1546 }
1547
1548 if (!color_node) {
1549 BKE_report(op->reports, RPT_WARNING, "Could not add a color node");
1550 return OPERATOR_CANCELLED;
1551 }
1552
1553 /* The Geometry Node color node stores the color value inside the node storage, while
1554 * the Compositing and Shading color nodes store it in the output socket. */
1555 if (snode->nodetree->type == NTREE_GEOMETRY) {
1556 NodeInputColor *input_color_storage = static_cast<NodeInputColor *>(color_node->storage);
1557 copy_v4_v4(input_color_storage->color, color);
1558 }
1559 else {
1560 bNodeSocket *sock = static_cast<bNodeSocket *>(color_node->outputs.first);
1561 if (!sock) {
1562 BKE_report(op->reports, RPT_WARNING, "Could not find node color socket");
1563 return OPERATOR_CANCELLED;
1564 }
1565
1566 bNodeSocketValueRGBA *socket_data = static_cast<bNodeSocketValueRGBA *>(sock->default_value);
1567 copy_v4_v4(socket_data->value, color);
1568 }
1569
1570 bke::node_set_active(*ntree, *color_node);
1571 BKE_main_ensure_invariants(*bmain, ntree->id);
1572
1573 return OPERATOR_FINISHED;
1574}
1575
1577{
1578 ARegion *region = CTX_wm_region(C);
1579 SpaceNode *snode = CTX_wm_space_node(C);
1580
1581 /* Convert mouse coordinates to v2d space. */
1583 event->mval[0],
1584 event->mval[1],
1585 &snode->runtime->cursor[0],
1586 &snode->runtime->cursor[1]);
1587
1588 snode->runtime->cursor[0] /= UI_SCALE_FAC;
1589 snode->runtime->cursor[1] /= UI_SCALE_FAC;
1590
1591 return node_add_color_exec(C, op);
1592}
1593
1595{
1596 const SpaceNode *snode = CTX_wm_space_node(C);
1597 return ED_operator_node_editable(C) &&
1599}
1600
1602{
1603 /* identifiers */
1604 ot->name = "Add Color";
1605 ot->description = "Add a color node to the current node editor";
1606 ot->idname = "NODE_OT_add_color";
1607
1608 /* callbacks */
1609 ot->exec = node_add_color_exec;
1610 ot->invoke = node_add_color_invoke;
1611 ot->poll = node_add_color_poll;
1612
1613 /* flags */
1615
1617 ot->srna, "color", 4, nullptr, 0.0, FLT_MAX, "Color", "Source color", 0.0, 1.0);
1619 ot->srna, "gamma", false, "Gamma Corrected", "The source color is gamma corrected");
1621 ot->srna, "has_alpha", false, "Has Alpha", "The source color contains an Alpha component");
1622}
1623
1624/* -------------------------------------------------------------------- */
1627
1629{
1630 Main *bmain = CTX_data_main(C);
1631
1632 bNodeTree *node_tree = bke::node_tree_add_tree(bmain, treename, idname);
1633 node_templateID_assign(C, node_tree);
1634
1635 return node_tree;
1636}
1637
1639{
1640 SpaceNode *snode = CTX_wm_space_node(C);
1642 PropertyRNA *prop;
1643 const char *idname;
1644 char treename_buf[MAX_ID_NAME - 2];
1645 const char *treename;
1646
1647 if (RNA_struct_property_is_set(op->ptr, "type")) {
1648 prop = RNA_struct_find_property(op->ptr, "type");
1649 RNA_property_enum_identifier(C, op->ptr, prop, RNA_property_enum_get(op->ptr, prop), &idname);
1650 }
1651 else if (snode) {
1652 idname = snode->tree_idname;
1653 }
1654 else {
1655 return OPERATOR_CANCELLED;
1656 }
1657
1658 if (!bke::node_tree_type_find(idname)) {
1659 BKE_reportf(op->reports, RPT_ERROR, "Node tree type %s undefined", idname);
1660 return OPERATOR_CANCELLED;
1661 }
1662
1663 if (RNA_struct_property_is_set(op->ptr, "name")) {
1664 RNA_string_get(op->ptr, "name", treename_buf);
1665 treename = treename_buf;
1666 }
1667 else {
1668 const bke::bNodeTreeType *type = bke::node_tree_type_find(idname);
1669 treename = type->ui_name.c_str();
1670 }
1671
1672 new_node_tree_impl(C, treename, idname);
1673
1675 return OPERATOR_FINISHED;
1676}
1677
1679 PointerRNA * /*ptr*/,
1680 PropertyRNA * /*prop*/,
1681 bool *r_free)
1682{
1683 return rna_node_tree_type_itemf(nullptr, nullptr, r_free);
1684}
1685
1687{
1688 PropertyRNA *prop;
1689
1690 /* identifiers */
1691 ot->name = "New Node Tree";
1692 ot->idname = "NODE_OT_new_node_tree";
1693 ot->description = "Create a new node tree";
1694
1695 /* API callbacks. */
1696 ot->exec = new_node_tree_exec;
1697
1698 /* flags */
1699 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1700
1701 prop = RNA_def_enum(ot->srna, "type", rna_enum_dummy_NULL_items, 0, "Tree Type", "");
1703 RNA_def_string(ot->srna, "name", "NodeTree", MAX_ID_NAME - 2, "Name", "");
1704}
1705
1707
1708/* -------------------------------------------------------------------- */
1711
1713{
1714 Main *bmain = CTX_data_main(C);
1715
1716 char tree_name[MAX_ID_NAME - 2];
1717 RNA_string_get(op->ptr, "name", tree_name);
1718
1719 bNodeTree *ntree = new_node_tree_impl(C, tree_name, "CompositorNodeTree");
1721
1724
1725 return OPERATOR_FINISHED;
1726}
1727
1729 wmOperator *op,
1730 const wmEvent * /* event */)
1731{
1732 PropertyRNA *prop;
1733 prop = RNA_struct_find_property(op->ptr, "name");
1734 if (!RNA_property_is_set(op->ptr, prop)) {
1735 RNA_property_string_set(op->ptr, prop, DATA_("Compositor Nodes"));
1736 }
1738}
1739
1741{
1742 /* identifiers */
1743 ot->name = "New Compositing Node Group";
1744 ot->idname = "NODE_OT_new_compositing_node_group";
1745 ot->description = "Create a new compositing node group and initialize it with default nodes";
1746
1747 /* api callbacks */
1750
1751 /* flags */
1752 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1753
1754 /* The default name of the new node tree can be translated if new data
1755 * translation is enabled, but since the user can choose it at invoke time,
1756 * the translation happens in the invoke callback instead of here. */
1757 RNA_def_string(ot->srna, "name", nullptr, MAX_ID_NAME - 2, "Name", "");
1758}
1759
1760/* -------------------------------------------------------------------- */
1763
1765{
1766 Main *bmain = CTX_data_main(C);
1767 Scene *scene = CTX_data_scene(C);
1769
1770 if (scene->compositing_node_group == nullptr) {
1771 return OPERATOR_CANCELLED;
1772 }
1773
1774 bNodeTree *node_tree = bke::node_tree_copy_tree(bmain, *scene->compositing_node_group);
1775
1776 node_templateID_assign(C, node_tree);
1777
1780
1781 return OPERATOR_FINISHED;
1782}
1783
1785{
1786 ot->name = "New Compositing Node Group";
1787 ot->idname = "NODE_OT_duplicate_compositing_node_group";
1788 ot->description = "Duplicate the currently assigned compositing node group.";
1789
1791
1792 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1793}
1794
1796
1797/* -------------------------------------------------------------------- */
1800
1802{
1803 BLI_assert(ntree.type == NTREE_COMPOSIT);
1804 BLI_assert(BLI_listbase_count(&ntree.nodes) == 0);
1805
1806 ntree.tree_interface.add_socket(
1807 "Image", "", "NodeSocketColor", NODE_INTERFACE_SOCKET_INPUT, nullptr);
1808 ntree.tree_interface.add_socket(
1809 "Mask", "", "NodeSocketColor", NODE_INTERFACE_SOCKET_INPUT, nullptr);
1810 ntree.tree_interface.add_socket(
1811 "Image", "", "NodeSocketColor", NODE_INTERFACE_SOCKET_OUTPUT, nullptr);
1812
1813 bNode *output_node = blender::bke::node_add_node(C, ntree, "NodeGroupOutput");
1814 output_node->location[0] = 200.0f;
1815 output_node->location[1] = 0.0f;
1816
1817 bNode *input_node = blender::bke::node_add_node(C, ntree, "NodeGroupInput");
1818 input_node->location[0] = -150.0f - input_node->width;
1819 input_node->location[1] = 0.0f;
1820 blender::bke::node_set_active(ntree, *input_node);
1821
1823 reroute->location[0] = 100.0f;
1824 reroute->location[1] = -35.0f;
1825
1827 viewer->location[0] = 200.0f;
1828 viewer->location[1] = -80.0f;
1829
1831 *input_node,
1832 *static_cast<bNodeSocket *>(input_node->outputs.first),
1833 *reroute,
1834 *static_cast<bNodeSocket *>(reroute->inputs.first));
1835
1837 *reroute,
1838 *static_cast<bNodeSocket *>(reroute->outputs.first),
1839 *output_node,
1840 *static_cast<bNodeSocket *>(output_node->inputs.first));
1841
1843 *reroute,
1844 *static_cast<bNodeSocket *>(reroute->outputs.first),
1845 *viewer,
1846 *static_cast<bNodeSocket *>(viewer->inputs.first));
1847
1849}
1850
1852{
1853 char tree_name[MAX_ID_NAME - 2];
1854 RNA_string_get(op->ptr, "name", tree_name);
1855
1856 bNodeTree *ntree = new_node_tree_impl(C, tree_name, "CompositorNodeTree");
1858
1861
1862 return OPERATOR_FINISHED;
1863}
1864
1866{
1867 operator_type->name = "New Compositor Sequencer Node Group";
1868 operator_type->idname = "NODE_OT_new_compositor_sequencer_node_group";
1869 operator_type->description = "Create a new compositor node group for sequencer";
1870
1872
1873 operator_type->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1874
1875 RNA_def_string(operator_type->srna,
1876 "name",
1877 DATA_("Sequencer Compositor Nodes"),
1878 MAX_ID_NAME - 2,
1879 "Name",
1880 "");
1881}
1882
1884
1885} // namespace blender::ed::space_node
Main runtime representation of an asset.
blender::Vector< PointerRNA > CTX_data_collection_get(const bContext *C, const char *member)
SpaceNode * CTX_wm_space_node(const bContext *C)
void CTX_wm_operator_poll_msg_set(bContext *C, const char *msg)
wmWindow * CTX_wm_window(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
#define IMA_SIGNAL_RELOAD
Definition BKE_image.hh:168
void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
void BKE_id_free_us(Main *bmain, void *idv) ATTR_NONNULL()
void id_us_plus(ID *id)
Definition lib_id.cc:358
void BKE_id_move_to_same_lib(Main &bmain, ID &id, const ID &owner_id)
Definition lib_id.cc:879
const char * BKE_id_name(const ID &id)
void id_us_min(ID *id)
Definition lib_id.cc:366
void BKE_main_ensure_invariants(Main &bmain, std::optional< blender::Span< ID * > > modified_ids=std::nullopt)
#define NODE_REROUTE
Definition BKE_node.hh:813
#define CMP_NODE_MASK
#define GEO_NODE_OBJECT_INFO
#define CMP_NODE_VIEWER
#define SH_NODE_TEX_IMAGE
#define GEO_NODE_IMAGE_TEXTURE
#define TEX_NODE_IMAGE
#define GEO_NODE_INPUT_MATERIAL
#define CMP_NODE_IMAGE
#define GEO_NODE_COLLECTION_INFO
void BKE_ntree_update_after_single_tree_change(Main &bmain, bNodeTree &modified_tree, const NodeTreeUpdateExtraParams &params={})
void BKE_ntree_update_tag_link_changed(bNodeTree *ntree)
void BKE_ntree_update_tag_socket_property(bNodeTree *ntree, bNodeSocket *socket)
void BKE_ntree_update_tag_node_property(bNodeTree *ntree, bNode *node)
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_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
float BLI_easing_cubic_ease_in_out(float time, float begin, float change, float duration)
Definition easing.cc:108
#define LISTBASE_FOREACH(type, var, list)
int BLI_listbase_count(const ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:524
int isect_seg_seg_v2_point(const float v0[2], const float v1[2], const float v2[2], const float v3[2], float r_vi[2])
MINLINE void copy_v4_v4(float r[4], const float a[4])
#define FILE_MAX
bool BLI_rctf_isect_pt_v(const struct rctf *rect, const float xy[2])
#define STR_ELEM(...)
Definition BLI_string.h:661
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:693
#define STRNCPY_UTF8(dst, src)
#define ELEM(...)
#define STREQ(a, b)
#define TIP_(msgid)
#define DATA_(msgid)
void DEG_relations_tag_update(Main *bmain)
#define MAX_ID_NAME
Definition DNA_ID.h:373
@ ID_IM
@ ID_NT
@ ID_MSK
@ ID_MA
@ ID_GR
@ ID_OB
Object groups, one object can be in many groups at once.
@ NODE_OPTIONS
@ NODE_SELECT
@ NTREE_TEXTURE
@ NTREE_CUSTOM
@ NTREE_SHADER
@ NTREE_GEOMETRY
@ NTREE_COMPOSIT
@ SOCK_OUT
@ SOCK_IN
@ SOCK_HIDDEN
@ SOCK_STRING
@ FILE_SORT_DEFAULT
@ FILE_SPECIAL
@ FILE_TYPE_MOVIE
@ FILE_TYPE_FOLDER
@ FILE_TYPE_IMAGE
@ FILE_DEFAULTDISPLAY
#define UI_SCALE_FAC
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
void ED_node_composit_default_init(const bContext *C, bNodeTree *ntree)
Definition node_edit.cc:601
void ED_node_set_active(Main *bmain, SpaceNode *snode, bNodeTree *ntree, bNode *node, bool *r_active_texture_changed)
Definition node_edit.cc:728
void ED_preview_kill_jobs(wmWindowManager *wm, Main *bmain)
bool ED_operator_node_editable(bContext *C)
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:618
BLI_INLINE void IMB_colormanagement_srgb_to_scene_linear_v3(float scene_linear[3], const float srgb[3])
Read Guarded memory(de)allocation.
#define RNA_BEGIN(sptr, itemptr, propname)
#define RNA_END
const EnumPropertyItem * rna_node_tree_type_itemf(void *data, bool(*poll)(void *data, blender::bke::bNodeTreeType *), bool *r_free)
@ PROP_SKIP_SAVE
Definition RNA_types.hh:344
@ PROP_HIDDEN
Definition RNA_types.hh:338
#define C
Definition RandGen.cpp:29
void UI_context_active_but_prop_get_templateID(const bContext *C, PointerRNA *r_ptr, PropertyRNA **r_prop)
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
@ WM_FILESEL_FILES
Definition WM_api.hh:1125
@ WM_FILESEL_DIRECTORY
Definition WM_api.hh:1122
@ WM_FILESEL_RELPATH
Definition WM_api.hh:1121
@ WM_FILESEL_FILEPATH
Definition WM_api.hh:1124
@ FILE_OPENFILE
Definition WM_api.hh:1133
#define NC_NODE
Definition WM_types.hh:394
#define NA_ADDED
Definition WM_types.hh:586
@ OPTYPE_INTERNAL
Definition WM_types.hh:202
@ OPTYPE_DEPENDS_ON_CURSOR
Definition WM_types.hh:218
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define NA_EDITED
Definition WM_types.hh:584
#define NC_IMAGE
Definition WM_types.hh:384
SubIterator begin() const
Definition BLI_map.hh:768
SubIterator end() const
Definition BLI_map.hh:778
constexpr IndexRange drop_back(int64_t n) const
Value & lookup_or_add_default(const Key &key)
Definition BLI_map.hh:639
ValueIterator values() const &
Definition BLI_map.hh:884
int64_t size() const
Definition BLI_map.hh:976
KeyIterator keys() const &
Definition BLI_map.hh:875
ItemIterator items() const &
Definition BLI_map.hh:902
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
constexpr const char * data() const
int64_t size() const
void append(const T &value)
const T & last(const int64_t n=0) const
bool is_empty() const
IndexRange index_range() const
nullptr float
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
T & get_item_as(bNodeTreeInterfaceItem &item)
void node_attach_node(bNodeTree &ntree, bNode &node, bNode &parent)
Definition node.cc:3978
bNodeTreeType * node_tree_type_find(StringRef idname)
Definition node.cc:2303
void node_tag_update_id(bNode &node)
Definition node.cc:4833
bNodeTree * node_tree_copy_tree(Main *bmain, const bNodeTree &ntree)
Definition node.cc:4114
bNodeSocket * node_find_socket(bNode &node, eNodeSocketInOut in_out, StringRef identifier)
Definition node.cc:2532
bNode * node_add_node(const bContext *C, bNodeTree &ntree, StringRef idname, std::optional< int > unique_identifier=std::nullopt)
Definition node.cc:3477
bool node_group_poll(const bNodeTree *nodetree, const bNodeTree *grouptree, const char **r_disabled_hint)
bool node_set_selected(bNode &node, bool select)
Definition node.cc:4695
bNode * node_add_static_node(const bContext *C, bNodeTree &ntree, int type)
Definition node.cc:3500
bNodeLink & node_add_link(bNodeTree &ntree, bNode &fromnode, bNodeSocket &fromsock, bNode &tonode, bNodeSocket &tosock)
Definition node.cc:3810
bNodeTree * node_tree_add_tree(Main *bmain, StringRef name, StringRef idname)
Definition node.cc:4085
void node_set_active(bNodeTree &ntree, bNode &node)
Definition node.cc:4724
void node_unique_name(bNodeTree &ntree, bNode &node)
Definition node.cc:3453
void operator_asset_reference_props_register(StructRNA &srna)
const asset_system::AssetRepresentation * operator_asset_reference_props_get_asset_from_all_library(const bContext &C, PointerRNA &ptr, ReportList *reports)
ID * asset_local_id_ensure_imported(Main &bmain, const asset_system::AssetRepresentation &asset, const std::optional< eAssetImportMethod > import_method=std::nullopt)
Vector< std::string > paths_from_operator_properties(PointerRNA *ptr)
Definition io_utils.cc:75
void NODE_OT_add_group_input_node(wmOperatorType *ot)
Definition node_add.cc:1476
void NODE_OT_add_object(wmOperatorType *ot)
Definition node_add.cc:734
static bool node_add_material_poll(bContext *C)
Definition node_add.cc:1181
NodeLinkData data[NODELINK_GROUP_SIZE]
Definition drawnode.cc:1863
static wmOperatorStatus node_add_group_exec(bContext *C, wmOperator *op)
Definition node_add.cc:337
void NODE_OT_add_mask(wmOperatorType *ot)
Definition node_add.cc:1110
static bool node_add_object_poll(bContext *C)
Definition node_add.cc:728
static wmOperatorStatus add_reroute_exec(bContext *C, wmOperator *op)
Definition node_add.cc:180
static void initialize_compositor_sequencer_node_group(const bContext *C, bNodeTree &ntree)
Definition node_add.cc:1801
bNode * add_static_node(const bContext &C, int type, const float2 &location)
Definition node_add.cc:97
static wmOperatorStatus node_add_color_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition node_add.cc:1576
static wmOperatorStatus node_add_mask_exec(bContext *C, wmOperator *op)
Definition node_add.cc:1082
static bool node_add_image_poll(bContext *C)
Definition node_add.cc:847
static wmOperatorStatus duplicate_compositing_node_group_exec(bContext *C, wmOperator *)
Definition node_add.cc:1764
static bool node_add_group_poll(bContext *C)
Definition node_add.cc:383
void NODE_OT_add_reroute(wmOperatorType *ot)
Definition node_add.cc:275
static wmOperatorStatus node_add_collection_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition node_add.cc:797
bool node_deselect_all(bNodeTree &node_tree)
void NODE_OT_new_compositing_node_group(wmOperatorType *ot)
Definition node_add.cc:1740
static wmOperatorStatus node_add_import_node_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition node_add.cc:1273
void NODE_OT_add_collection(wmOperatorType *ot)
Definition node_add.cc:823
static void node_templateID_assign(bContext *C, bNodeTree *node_tree)
Definition node_add.cc:120
bNode * add_node(const bContext &C, const StringRef idname, const float2 &location)
Definition node_add.cc:77
static wmOperatorStatus new_compositing_node_group_exec(bContext *C, wmOperator *op)
Definition node_add.cc:1712
static wmOperatorStatus node_add_group_input_node_exec(bContext *C, wmOperator *op)
Definition node_add.cc:1328
void NODE_OT_add_group_asset(wmOperatorType *ot)
Definition node_add.cc:635
static wmOperatorStatus node_add_material_exec(bContext *C, wmOperator *op)
Definition node_add.cc:1133
static void position_node_based_on_mouse(bNode &node, const float2 &location)
Definition node_add.cc:71
static bool node_add_color_poll(bContext *C)
Definition node_add.cc:1594
static wmOperatorStatus node_add_collection_exec(bContext *C, wmOperator *op)
Definition node_add.cc:758
void NODE_OT_duplicate_compositing_node_group(wmOperatorType *ot)
Definition node_add.cc:1784
static wmOperatorStatus node_swap_group_asset_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition node_add.cc:547
void NODE_OT_swap_group_asset(wmOperatorType *ot)
Definition node_add.cc:650
static const EnumPropertyItem * new_node_tree_type_itemf(bContext *, PointerRNA *, PropertyRNA *, bool *r_free)
Definition node_add.cc:1678
static bool node_add_import_node_poll(bContext *C)
Definition node_add.cc:1293
static wmOperatorStatus new_compositing_node_group_invoke(bContext *C, wmOperator *op, const wmEvent *)
Definition node_add.cc:1728
static bNodeTree * new_node_tree_impl(bContext *C, StringRef treename, StringRef idname)
Definition node_add.cc:1628
void NODE_OT_add_color(wmOperatorType *ot)
Definition node_add.cc:1601
static wmOperatorStatus node_add_group_asset_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition node_add.cc:511
static wmOperatorStatus node_add_material_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition node_add.cc:1163
bool node_link_is_hidden_or_dimmed(const View2D &v2d, const bNodeLink &link)
void tree_update(const bContext *C)
Definition node_draw.cc:186
static wmOperatorStatus new_compositor_sequencer_node_group_exec(bContext *C, wmOperator *op)
Definition node_add.cc:1851
std::optional< float2 > link_path_intersection(const bNodeLink &link, const Span< float2 > path)
Definition node_add.cc:156
VectorSet< bNode * > get_selected_nodes(bNodeTree &node_tree)
static bool node_swap_group_poll(bContext *C)
Definition node_add.cc:397
void NODE_OT_new_compositor_sequencer_node_group(wmOperatorType *operator_type)
Definition node_add.cc:1865
static bool node_group_add_poll(const bNodeTree &node_tree, const bNodeTree &node_group, ReportList &reports)
Definition node_add.cc:305
static wmOperatorStatus node_add_object_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition node_add.cc:710
void node_link_bezier_points_evaluated(const bNodeLink &link, std::array< float2, NODE_LINK_RESOL+1 > &coords)
Definition drawnode.cc:1683
static bool node_add_mask_poll(bContext *C)
Definition node_add.cc:1075
static wmOperatorStatus node_add_object_exec(bContext *C, wmOperator *op)
Definition node_add.cc:671
static bool node_add_group_input_node_poll(bContext *C)
Definition node_add.cc:1438
void NODE_OT_add_import_node(wmOperatorType *ot)
Definition node_add.cc:1299
static std::string node_add_group_asset_get_description(bContext *C, wmOperatorType *, PointerRNA *ptr)
Definition node_add.cc:619
void NODE_OT_add_image(wmOperatorType *ot)
Definition node_add.cc:1042
static wmOperatorStatus new_node_tree_exec(bContext *C, wmOperator *op)
Definition node_add.cc:1638
void NODE_OT_add_group(wmOperatorType *ot)
Definition node_add.cc:436
static wmOperatorStatus node_add_nodes_modal(bContext *C, wmOperator *op, const wmEvent *event)
Definition node_add.cc:868
static wmOperatorStatus node_add_color_exec(bContext *C, wmOperator *op)
Definition node_add.cc:1513
static bool node_add_collection_poll(bContext *C)
Definition node_add.cc:817
static wmOperatorStatus node_add_import_node_exec(bContext *C, wmOperator *op)
Definition node_add.cc:1211
static wmOperatorStatus node_add_group_input_node_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition node_add.cc:1418
static wmOperatorStatus node_add_group_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition node_add.cc:418
void NODE_OT_add_material(wmOperatorType *ot)
Definition node_add.cc:1187
static wmOperatorStatus node_add_image_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition node_add.cc:1012
static wmOperatorStatus node_add_image_exec(bContext *C, wmOperator *op)
Definition node_add.cc:910
void NODE_OT_new_node_tree(wmOperatorType *ot)
Definition node_add.cc:1686
StringRef node_group_idname(const bContext *C)
static bool add_node_group_asset(const bContext &C, const asset_system::AssetRepresentation &asset, ReportList &reports)
Definition node_add.cc:464
T min(const T &a, const T &b)
VecBase< float, 2 > float2
#define NODE_LINK_RESOL
#define NODE_DY
bool RNA_property_enum_identifier(bContext *C, PointerRNA *ptr, PropertyRNA *prop, const int value, const char **r_identifier)
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
void RNA_property_pointer_set(PointerRNA *ptr, PropertyRNA *prop, PointerRNA ptr_value, ReportList *reports)
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
void RNA_property_update(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
void RNA_collection_add(PointerRNA *ptr, const char *name, PointerRNA *r_value)
int RNA_int_get(PointerRNA *ptr, const char *name)
std::string RNA_string_get(PointerRNA *ptr, const char *name)
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop)
bool RNA_struct_property_is_set(PointerRNA *ptr, const char *identifier)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
PointerRNA RNA_id_pointer_create(ID *id)
void RNA_property_string_set(PointerRNA *ptr, PropertyRNA *prop, const char *value)
PropertyRNA * RNA_def_string(StructOrFunctionRNA *cont_, const char *identifier, const char *default_value, const int maxlen, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_float_color(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)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_collection_runtime(StructOrFunctionRNA *cont_, const char *identifier, StructRNA *type, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
void RNA_def_enum_funcs(PropertyRNA *prop, EnumPropertyItemFunc itemfunc)
PropertyRNA * RNA_def_string_dir_path(StructOrFunctionRNA *cont_, const char *identifier, const char *default_value, const int maxlen, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, const int default_value, const int hardmin, const int hardmax, const char *ui_name, const char *ui_description, const int softmin, const int softmax)
const EnumPropertyItem rna_enum_dummy_NULL_items[]
Definition rna_rna.cc:26
#define FLT_MAX
Definition stdcycles.h:14
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
void * first
struct bNodeTree * compositing_node_group
char tree_idname[64]
SpaceNode_Runtime * runtime
struct bNodeTree * edittree
struct bNodeTree * nodetree
struct Collection * value
void * default_value
char idname[64]
char idname[64]
int default_group_node_width
bNodeTreeInterface tree_interface
ListBase nodes
ListBase links
float location[2]
bNodeTypeHandle * typeinfo
float width
ListBase inputs
struct ID * id
char name[64]
bNodeRuntimeHandle * runtime
void * storage
ListBase outputs
wmEventType type
Definition WM_types.hh:757
int mval[2]
Definition WM_types.hh:763
void * customdata
Definition WM_types.hh:807
const char * name
Definition WM_types.hh:1033
wmOperatorStatus(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1049
const char * idname
Definition WM_types.hh:1035
const char * description
Definition WM_types.hh:1039
StructRNA * srna
Definition WM_types.hh:1127
struct ReportList * reports
struct PointerRNA * ptr
i
Definition text_draw.cc:230
@ WM_CURSOR_CROSS
Definition wm_cursors.hh:26
wmOperatorStatus WM_operator_name_call_ptr(bContext *C, wmOperatorType *ot, blender::wm::OpCallContext context, PointerRNA *properties, const wmEvent *event)
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
@ TIMER
PointerRNA * ptr
Definition wm_files.cc:4238
wmOperatorType * ot
Definition wm_files.cc:4237
void WM_gesture_lines_cancel(bContext *C, wmOperator *op)
wmOperatorStatus WM_gesture_lines_modal(bContext *C, wmOperator *op, const wmEvent *event)
wmOperatorStatus WM_gesture_lines_invoke(bContext *C, wmOperator *op, const wmEvent *event)
bool WM_operator_properties_id_lookup_is_set(PointerRNA *ptr)
ID * WM_operator_properties_id_lookup_from_name_or_session_uid(Main *bmain, PointerRNA *ptr, const ID_Type type)
void WM_operator_properties_filesel(wmOperatorType *ot, const int filter, const short type, const eFileSel_Action action, const eFileSel_Flag flag, const short display, const short sort)
void WM_operator_properties_id_lookup(wmOperatorType *ot, const bool add_name_prop)
wmOperatorType * WM_operatortype_find(const char *idname, bool quiet)
void WM_operator_properties_create_ptr(PointerRNA *ptr, wmOperatorType *ot)
void WM_operator_properties_free(PointerRNA *ptr)
ID * WM_operator_drop_load_path(bContext *C, wmOperator *op, const short idcode)
wmOperatorStatus WM_operator_filesel(bContext *C, wmOperator *op, const wmEvent *)
wmTimer * WM_event_timer_add(wmWindowManager *wm, wmWindow *win, const wmEventType event_type, const double time_step)
void WM_event_timer_remove(wmWindowManager *wm, wmWindow *, wmTimer *timer)