Blender  V2.93
node_templates.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
21 #include <stdlib.h>
22 #include <string.h>
23 
24 #include "MEM_guardedalloc.h"
25 
26 #include "DNA_node_types.h"
27 #include "DNA_screen_types.h"
28 
29 #include "BLI_array.h"
30 #include "BLI_listbase.h"
31 #include "BLI_string.h"
32 
33 #include "BLT_translation.h"
34 
35 #include "BKE_context.h"
36 #include "BKE_lib_id.h"
37 #include "BKE_main.h"
38 
39 #include "RNA_access.h"
40 
41 #include "NOD_socket.h"
42 
43 #include "../interface/interface_intern.h" /* XXX bad level */
44 #include "UI_interface.h"
45 
46 #include "ED_node.h" /* own include */
47 #include "node_intern.h"
48 
49 #include "ED_undo.h"
50 
51 /************************* Node Socket Manipulation **************************/
52 
53 /* describes an instance of a node type and a specific socket to link */
54 typedef struct NodeLinkItem {
55  int socket_index; /* index for linking */
56  int socket_type; /* socket type for compatibility check */
57  const char *socket_name; /* ui label of the socket */
58  const char *node_name; /* ui label of the node */
59 
60  /* extra settings */
61  bNodeTree *ngroup; /* group node tree */
63 
64 /* Compare an existing node to a link item to see if it can be reused.
65  * item must be for the same node type!
66  * XXX should become a node type callback
67  */
69 {
70  if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) {
71  return (node->id == (ID *)item->ngroup);
72  }
73  return true;
74 }
75 
76 static void node_link_item_apply(Main *bmain, bNode *node, NodeLinkItem *item)
77 {
78  if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) {
79  node->id = (ID *)item->ngroup;
80  ntreeUpdateTree(bmain, item->ngroup);
81  }
82  else {
83  /* nothing to do for now */
84  }
85 
86  if (node->id) {
87  id_us_plus(node->id);
88  }
89 }
90 
92 {
93  bNodeSocket *input;
94 
95  if (!node || (node->flag & NODE_TEST)) {
96  return; /* in case of cycles */
97  }
98 
99  node->flag |= NODE_TEST;
100 
101  for (input = node->inputs.first; input; input = input->next) {
102  if (input->link) {
104  }
105  }
106 }
107 
109 {
110  bNodeSocket *input;
111 
112  if (!node || !(node->flag & NODE_TEST)) {
113  return; /* in case of cycles */
114  }
115 
116  node->flag &= ~NODE_TEST;
117 
118  for (input = node->inputs.first; input; input = input->next) {
119  if (input->link) {
121  }
122  }
123 }
124 
125 static void node_remove_linked(Main *bmain, bNodeTree *ntree, bNode *rem_node)
126 {
127  bNode *node, *next;
128  bNodeSocket *sock;
129 
130  if (!rem_node) {
131  return;
132  }
133 
134  /* tag linked nodes to be removed */
135  for (node = ntree->nodes.first; node; node = node->next) {
136  node->flag &= ~NODE_TEST;
137  }
138 
139  node_tag_recursive(rem_node);
140 
141  /* clear tags on nodes that are still used by other nodes */
142  for (node = ntree->nodes.first; node; node = node->next) {
143  if (!(node->flag & NODE_TEST)) {
144  for (sock = node->inputs.first; sock; sock = sock->next) {
145  if (sock->link && sock->link->fromnode != rem_node) {
147  }
148  }
149  }
150  }
151 
152  /* remove nodes */
153  for (node = ntree->nodes.first; node; node = next) {
154  next = node->next;
155 
156  if (node->flag & NODE_TEST) {
157  nodeRemoveNode(bmain, ntree, node, true);
158  }
159  }
160 }
161 
162 /* disconnect socket from the node it is connected to */
163 static void node_socket_disconnect(Main *bmain,
164  bNodeTree *ntree,
165  bNode *node_to,
166  bNodeSocket *sock_to)
167 {
168  if (!sock_to->link) {
169  return;
170  }
171 
172  nodeRemLink(ntree, sock_to->link);
173  sock_to->flag |= SOCK_COLLAPSED;
174 
175  nodeUpdate(ntree, node_to);
176  ntreeUpdateTree(bmain, ntree);
177 
178  ED_node_tag_update_nodetree(bmain, ntree, node_to);
179 }
180 
181 /* remove all nodes connected to this socket, if they aren't connected to other nodes */
182 static void node_socket_remove(Main *bmain, bNodeTree *ntree, bNode *node_to, bNodeSocket *sock_to)
183 {
184  if (!sock_to->link) {
185  return;
186  }
187 
188  node_remove_linked(bmain, ntree, sock_to->link->fromnode);
189  sock_to->flag |= SOCK_COLLAPSED;
190 
191  nodeUpdate(ntree, node_to);
192  ntreeUpdateTree(bmain, ntree);
193 
194  ED_node_tag_update_nodetree(bmain, ntree, node_to);
195 }
196 
197 /* add new node connected to this socket, or replace an existing one */
198 static void node_socket_add_replace(const bContext *C,
199  bNodeTree *ntree,
200  bNode *node_to,
201  bNodeSocket *sock_to,
202  int type,
203  NodeLinkItem *item)
204 {
205  Main *bmain = CTX_data_main(C);
206  bNode *node_from;
207  bNodeSocket *sock_from_tmp;
208  bNode *node_prev = NULL;
209 
210  /* unlink existing node */
211  if (sock_to->link) {
212  node_prev = sock_to->link->fromnode;
213  nodeRemLink(ntree, sock_to->link);
214  }
215 
216  /* find existing node that we can use */
217  for (node_from = ntree->nodes.first; node_from; node_from = node_from->next) {
218  if (node_from->type == type) {
219  break;
220  }
221  }
222 
223  if (node_from) {
224  if (node_from->inputs.first || node_from->typeinfo->draw_buttons ||
225  node_from->typeinfo->draw_buttons_ex) {
226  node_from = NULL;
227  }
228  }
229 
230  if (node_prev && node_prev->type == type && node_link_item_compare(node_prev, item)) {
231  /* keep the previous node if it's the same type */
232  node_from = node_prev;
233  }
234  else if (!node_from) {
235  node_from = nodeAddStaticNode(C, ntree, type);
236  if (node_prev != NULL) {
237  /* If we're replacing existing node, use its location. */
238  node_from->locx = node_prev->locx;
239  node_from->locy = node_prev->locy;
240  node_from->offsetx = node_prev->offsetx;
241  node_from->offsety = node_prev->offsety;
242  }
243  else {
244  sock_from_tmp = BLI_findlink(&node_from->outputs, item->socket_index);
245  nodePositionRelative(node_from, node_to, sock_from_tmp, sock_to);
246  }
247 
248  node_link_item_apply(bmain, node_from, item);
249  }
250 
251  nodeSetActive(ntree, node_from);
252 
253  /* add link */
254  sock_from_tmp = BLI_findlink(&node_from->outputs, item->socket_index);
255  nodeAddLink(ntree, node_from, sock_from_tmp, node_to, sock_to);
256  sock_to->flag &= ~SOCK_COLLAPSED;
257 
258  /* copy input sockets from previous node */
259  if (node_prev && node_from != node_prev) {
260  bNodeSocket *sock_prev, *sock_from;
261 
262  for (sock_prev = node_prev->inputs.first; sock_prev; sock_prev = sock_prev->next) {
263  for (sock_from = node_from->inputs.first; sock_from; sock_from = sock_from->next) {
264  if (nodeCountSocketLinks(ntree, sock_from) >= nodeSocketLinkLimit(sock_from)) {
265  continue;
266  }
267 
268  if (STREQ(sock_prev->name, sock_from->name) && sock_prev->type == sock_from->type) {
269  bNodeLink *link = sock_prev->link;
270 
271  if (link && link->fromnode) {
272  nodeAddLink(ntree, link->fromnode, link->fromsock, node_from, sock_from);
273  nodeRemLink(ntree, link);
274  }
275 
276  node_socket_copy_default_value(sock_from, sock_prev);
277  }
278  }
279  }
280 
281  /* also preserve mapping for texture nodes */
282  if (node_from->typeinfo->nclass == NODE_CLASS_TEXTURE &&
283  node_prev->typeinfo->nclass == NODE_CLASS_TEXTURE &&
284  /* White noise texture node does not have NodeTexBase. */
285  node_from->storage != NULL && node_prev->storage != NULL) {
286  memcpy(node_from->storage, node_prev->storage, sizeof(NodeTexBase));
287  }
288 
289  /* remove node */
290  node_remove_linked(bmain, ntree, node_prev);
291  }
292 
293  nodeUpdate(ntree, node_from);
294  nodeUpdate(ntree, node_to);
296 
298 }
299 
300 /****************************** Node Link Menu *******************************/
301 
302 // #define UI_NODE_LINK_ADD 0
303 #define UI_NODE_LINK_DISCONNECT -1
304 #define UI_NODE_LINK_REMOVE -2
305 
306 typedef struct NodeLinkArg {
312 
315 
318 
320  int in_out,
321  NodeLinkItem **r_items,
322  int *r_totitems)
323 {
324  /* XXX this should become a callback for node types! */
325  NodeLinkItem *items = NULL;
326  int totitems = 0;
327 
328  if (arg->node_type->type == NODE_GROUP) {
329  bNodeTree *ngroup;
330  int i;
331 
332  for (ngroup = arg->bmain->nodetrees.first; ngroup; ngroup = ngroup->id.next) {
333  const char *disabled_hint;
334  if ((ngroup->type != arg->ntree->type) ||
335  !nodeGroupPoll(arg->ntree, ngroup, &disabled_hint)) {
336  continue;
337  }
338 
339  ListBase *lb = ((in_out == SOCK_IN) ? &ngroup->inputs : &ngroup->outputs);
340  totitems += BLI_listbase_count(lb);
341  }
342 
343  if (totitems > 0) {
344  items = MEM_callocN(sizeof(NodeLinkItem) * totitems, "ui node link items");
345 
346  i = 0;
347  for (ngroup = arg->bmain->nodetrees.first; ngroup; ngroup = ngroup->id.next) {
348  const char *disabled_hint;
349  if ((ngroup->type != arg->ntree->type) ||
350  !nodeGroupPoll(arg->ntree, ngroup, &disabled_hint)) {
351  continue;
352  }
353 
354  ListBase *lb = (in_out == SOCK_IN ? &ngroup->inputs : &ngroup->outputs);
355  bNodeSocket *stemp;
356  int index;
357  for (stemp = lb->first, index = 0; stemp; stemp = stemp->next, index++, i++) {
358  NodeLinkItem *item = &items[i];
359 
360  item->socket_index = index;
361  /* note: int stemp->type is not fully reliable, not used for node group
362  * interface sockets. use the typeinfo->type instead.
363  */
364  item->socket_type = stemp->typeinfo->type;
365  item->socket_name = stemp->name;
366  item->node_name = ngroup->id.name + 2;
367  item->ngroup = ngroup;
368  }
369  }
370  }
371  }
372  else {
373  bNodeSocketTemplate *socket_templates = (in_out == SOCK_IN ? arg->node_type->inputs :
374  arg->node_type->outputs);
375  bNodeSocketTemplate *stemp;
376  int i;
377 
378  for (stemp = socket_templates; stemp && stemp->type != -1; stemp++) {
379  totitems++;
380  }
381 
382  if (totitems > 0) {
383  items = MEM_callocN(sizeof(NodeLinkItem) * totitems, "ui node link items");
384 
385  i = 0;
386  for (stemp = socket_templates; stemp && stemp->type != -1; stemp++, i++) {
387  NodeLinkItem *item = &items[i];
388 
389  item->socket_index = i;
390  item->socket_type = stemp->type;
391  item->socket_name = stemp->name;
392  item->node_name = arg->node_type->ui_name;
393  }
394  }
395  }
396 
397  *r_items = items;
398  *r_totitems = totitems;
399 }
400 
401 static void ui_node_link(bContext *C, void *arg_p, void *event_p)
402 {
403  NodeLinkArg *arg = (NodeLinkArg *)arg_p;
404  Main *bmain = arg->bmain;
405  bNode *node_to = arg->node;
406  bNodeSocket *sock_to = arg->sock;
407  bNodeTree *ntree = arg->ntree;
408  int event = POINTER_AS_INT(event_p);
409 
410  if (event == UI_NODE_LINK_DISCONNECT) {
411  node_socket_disconnect(bmain, ntree, node_to, sock_to);
412  }
413  else if (event == UI_NODE_LINK_REMOVE) {
414  node_socket_remove(bmain, ntree, node_to, sock_to);
415  }
416  else {
417  node_socket_add_replace(C, ntree, node_to, sock_to, arg->node_type->type, &arg->item);
418  }
419 
420  ED_undo_push(C, "Node input modify");
421 }
422 
424 {
425  if (sock->link && sock->link->fromnode) {
426  bNode *node = sock->link->fromnode;
427  char node_name[UI_MAX_NAME_STR];
428 
429  nodeLabel(ntree, node, node_name, sizeof(node_name));
430 
431  if (BLI_listbase_is_empty(&node->inputs) && node->outputs.first != node->outputs.last) {
432  BLI_snprintf(
433  name, UI_MAX_NAME_STR, "%s | %s", IFACE_(node_name), IFACE_(sock->link->fromsock->name));
434  }
435  else {
436  BLI_strncpy(name, IFACE_(node_name), UI_MAX_NAME_STR);
437  }
438  }
439  else if (sock->type == SOCK_SHADER) {
440  BLI_strncpy(name, IFACE_("None"), UI_MAX_NAME_STR);
441  }
442  else {
443  BLI_strncpy(name, IFACE_("Default"), UI_MAX_NAME_STR);
444  }
445 }
446 
447 static int ui_compatible_sockets(int typeA, int typeB)
448 {
449  return (typeA == typeB);
450 }
451 
452 static int ui_node_item_name_compare(const void *a, const void *b)
453 {
454  const bNodeType *type_a = *(const bNodeType **)a;
455  const bNodeType *type_b = *(const bNodeType **)b;
456  return BLI_strcasecmp_natural(type_a->ui_name, type_b->ui_name);
457 }
458 
459 static bool ui_node_item_special_poll(const bNodeTree *UNUSED(ntree), const bNodeType *ntype)
460 {
461  if (STREQ(ntype->idname, "ShaderNodeUVAlongStroke")) {
462  /* TODO(sergey): Currently we don't have Freestyle nodes edited from
463  * the buttons context, so can ignore its nodes completely.
464  *
465  * However, we might want to do some extra checks here later.
466  */
467  return false;
468  }
469  return true;
470 }
471 
472 static void ui_node_menu_column(NodeLinkArg *arg, int nclass, const char *cname)
473 {
474  bNodeTree *ntree = arg->ntree;
475  bNodeSocket *sock = arg->sock;
476  uiLayout *layout = arg->layout;
477  uiLayout *column = NULL;
478  uiBlock *block = uiLayoutGetBlock(layout);
479  uiBut *but;
480  NodeLinkArg *argN;
481  int first = 1;
482 
483  /* generate array of node types sorted by UI name */
484  bNodeType **sorted_ntypes = NULL;
485  BLI_array_declare(sorted_ntypes);
486 
487  NODE_TYPES_BEGIN (ntype) {
488  const char *disabled_hint;
489  if (!(ntype->poll && ntype->poll(ntype, ntree, &disabled_hint))) {
490  continue;
491  }
492 
493  if (ntype->nclass != nclass) {
494  continue;
495  }
496 
497  if (!ui_node_item_special_poll(ntree, ntype)) {
498  continue;
499  }
500 
501  BLI_array_append(sorted_ntypes, ntype);
502  }
504 
505  qsort(
506  sorted_ntypes, BLI_array_len(sorted_ntypes), sizeof(bNodeType *), ui_node_item_name_compare);
507 
508  /* generate UI */
509  for (int j = 0; j < BLI_array_len(sorted_ntypes); j++) {
510  bNodeType *ntype = sorted_ntypes[j];
511  NodeLinkItem *items;
512  int totitems;
513  char name[UI_MAX_NAME_STR];
514  const char *cur_node_name = NULL;
515  int num = 0;
516  int icon = ICON_NONE;
517 
518  arg->node_type = ntype;
519 
520  ui_node_link_items(arg, SOCK_OUT, &items, &totitems);
521 
522  for (int i = 0; i < totitems; i++) {
523  if (ui_compatible_sockets(items[i].socket_type, sock->type)) {
524  num++;
525  }
526  }
527 
528  for (int i = 0; i < totitems; i++) {
529  if (!ui_compatible_sockets(items[i].socket_type, sock->type)) {
530  continue;
531  }
532 
533  if (first) {
534  column = uiLayoutColumn(layout, 0);
535  UI_block_layout_set_current(block, column);
536 
537  uiItemL(column, IFACE_(cname), ICON_NODE);
538  but = block->buttons.last;
539 
540  first = 0;
541  }
542 
543  if (num > 1) {
544  if (!cur_node_name || !STREQ(cur_node_name, items[i].node_name)) {
545  cur_node_name = items[i].node_name;
546  /* XXX Do not use uiItemL here,
547  * it would add an empty icon as we are in a menu! */
548  uiDefBut(block,
550  0,
551  IFACE_(cur_node_name),
552  0,
553  0,
554  UI_UNIT_X * 4,
555  UI_UNIT_Y,
556  NULL,
557  0.0,
558  0.0,
559  0.0,
560  0.0,
561  "");
562  }
563 
564  BLI_snprintf(name, UI_MAX_NAME_STR, "%s", IFACE_(items[i].socket_name));
565  icon = ICON_BLANK1;
566  }
567  else {
568  BLI_strncpy(name, IFACE_(items[i].node_name), UI_MAX_NAME_STR);
569  icon = ICON_NONE;
570  }
571 
572  but = uiDefIconTextBut(block,
573  UI_BTYPE_BUT,
574  0,
575  icon,
576  name,
577  0,
578  0,
579  UI_UNIT_X * 4,
580  UI_UNIT_Y,
581  NULL,
582  0.0,
583  0.0,
584  0.0,
585  0.0,
586  TIP_("Add node to input"));
587 
588  argN = MEM_dupallocN(arg);
589  argN->item = items[i];
590  UI_but_funcN_set(but, ui_node_link, argN, NULL);
591  }
592 
593  if (items) {
594  MEM_freeN(items);
595  }
596  }
597 
598  BLI_array_free(sorted_ntypes);
599 }
600 
601 static void node_menu_column_foreach_cb(void *calldata, int nclass, const char *name)
602 {
603  NodeLinkArg *arg = (NodeLinkArg *)calldata;
604 
605  if (!ELEM(nclass, NODE_CLASS_GROUP, NODE_CLASS_LAYOUT)) {
606  ui_node_menu_column(arg, nclass, name);
607  }
608 }
609 
610 static void ui_template_node_link_menu(bContext *C, uiLayout *layout, void *but_p)
611 {
612  Main *bmain = CTX_data_main(C);
614  uiBlock *block = uiLayoutGetBlock(layout);
615  uiBut *but = (uiBut *)but_p;
616  uiLayout *split, *column;
617  NodeLinkArg *arg = (NodeLinkArg *)but->func_argN;
618  bNodeSocket *sock = arg->sock;
619  bNodeTreeType *ntreetype = arg->ntree->typeinfo;
620 
622  UI_block_layout_set_current(block, layout);
623  split = uiLayoutSplit(layout, 0.0f, false);
624 
625  arg->bmain = bmain;
626  arg->scene = scene;
627  arg->layout = split;
628 
629  if (ntreetype && ntreetype->foreach_nodeclass) {
630  ntreetype->foreach_nodeclass(scene, arg, node_menu_column_foreach_cb);
631  }
632 
633  column = uiLayoutColumn(split, false);
634  UI_block_layout_set_current(block, column);
635 
636  if (sock->link) {
637  uiItemL(column, IFACE_("Link"), ICON_NONE);
638  but = block->buttons.last;
639  but->drawflag = UI_BUT_TEXT_LEFT;
640 
641  but = uiDefBut(block,
642  UI_BTYPE_BUT,
643  0,
644  IFACE_("Remove"),
645  0,
646  0,
647  UI_UNIT_X * 4,
648  UI_UNIT_Y,
649  NULL,
650  0.0,
651  0.0,
652  0.0,
653  0.0,
654  TIP_("Remove nodes connected to the input"));
656 
657  but = uiDefBut(block,
658  UI_BTYPE_BUT,
659  0,
660  IFACE_("Disconnect"),
661  0,
662  0,
663  UI_UNIT_X * 4,
664  UI_UNIT_Y,
665  NULL,
666  0.0,
667  0.0,
668  0.0,
669  0.0,
670  TIP_("Disconnect nodes connected to the input"));
673  }
674 
675  ui_node_menu_column(arg, NODE_CLASS_GROUP, N_("Group"));
676 }
677 
679  uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *input)
680 {
681  uiBlock *block = uiLayoutGetBlock(layout);
682  NodeLinkArg *arg;
683  uiBut *but;
684  float socket_col[4];
685 
686  arg = MEM_callocN(sizeof(NodeLinkArg), "NodeLinkArg");
687  arg->ntree = ntree;
688  arg->node = node;
689  arg->sock = input;
690 
691  PointerRNA node_ptr;
692  RNA_pointer_create((ID *)ntree, &RNA_Node, node, &node_ptr);
693  node_socket_color_get(C, ntree, &node_ptr, input, socket_col);
694 
695  UI_block_layout_set_current(block, layout);
696 
697  if (input->link || input->type == SOCK_SHADER || (input->flag & SOCK_HIDE_VALUE)) {
698  char name[UI_MAX_NAME_STR];
699  ui_node_sock_name(ntree, input, name);
700  but = uiDefMenuBut(
701  block, ui_template_node_link_menu, NULL, name, 0, 0, UI_UNIT_X * 4, UI_UNIT_Y, "");
702  }
703  else {
704  but = uiDefIconMenuBut(
705  block, ui_template_node_link_menu, NULL, ICON_NONE, 0, 0, UI_UNIT_X, UI_UNIT_Y, "");
706  }
707 
709  UI_but_node_link_set(but, input, socket_col);
711 
712  but->poin = (char *)but;
713  but->func_argN = arg;
714 
715  if (input->link && input->link->fromnode) {
716  if (input->link->fromnode->flag & NODE_ACTIVE_TEXTURE) {
717  but->flag |= UI_BUT_NODE_ACTIVE;
718  }
719  }
720 }
721 
722 /**************************** Node Tree Layout *******************************/
723 
724 static void ui_node_draw_input(
725  uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *input, int depth);
726 
727 static void ui_node_draw_node(
728  uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, int depth)
729 {
730  bNodeSocket *input;
731  PointerRNA nodeptr;
732 
733  RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr);
734 
735  if (node->typeinfo->draw_buttons) {
736  if (node->type != NODE_GROUP) {
737  uiLayoutSetPropSep(layout, true);
738  node->typeinfo->draw_buttons(layout, C, &nodeptr);
739  }
740  }
741 
742  for (input = node->inputs.first; input; input = input->next) {
743  ui_node_draw_input(layout, C, ntree, node, input, depth + 1);
744  }
745 }
746 
747 static void ui_node_draw_input(
748  uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *input, int depth)
749 {
750  PointerRNA inputptr, nodeptr;
751  uiBlock *block = uiLayoutGetBlock(layout);
752  uiLayout *row = NULL;
753  bNode *lnode;
754  bool dependency_loop;
755 
756  if (input->flag & SOCK_UNAVAIL) {
757  return;
758  }
759 
760  /* to avoid eternal loops on cyclic dependencies */
761  node->flag |= NODE_TEST;
762  lnode = (input->link) ? input->link->fromnode : NULL;
763 
764  dependency_loop = (lnode && (lnode->flag & NODE_TEST));
765  if (dependency_loop) {
766  lnode = NULL;
767  }
768 
769  /* socket RNA pointer */
770  RNA_pointer_create(&ntree->id, &RNA_NodeSocket, input, &inputptr);
771  RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr);
772 
773  row = uiLayoutRow(layout, true);
774  /* Decorations are added manually here. */
775  uiLayoutSetPropDecorate(row, false);
776 
778  /* Empty decorator item for alignment. */
779  bool add_dummy_decorator = false;
780 
781  {
782  uiLayout *sub = uiLayoutRow(split_wrapper.label_column, true);
783 
784  if (depth > 0) {
786 
787  if (lnode &&
788  (lnode->inputs.first || (lnode->typeinfo->draw_buttons && lnode->type != NODE_GROUP))) {
789  int icon = (input->flag & SOCK_COLLAPSED) ? ICON_DISCLOSURE_TRI_RIGHT :
790  ICON_DISCLOSURE_TRI_DOWN;
791  uiItemR(sub, &inputptr, "show_expanded", UI_ITEM_R_ICON_ONLY, "", icon);
792  }
793 
795  }
796 
797  sub = uiLayoutRow(sub, true);
799  uiItemL(sub, IFACE_(input->name), ICON_NONE);
800  }
801 
802  if (dependency_loop) {
803  uiItemL(row, IFACE_("Dependency Loop"), ICON_ERROR);
804  add_dummy_decorator = true;
805  }
806  else if (lnode) {
807  /* input linked to a node */
808  uiTemplateNodeLink(row, C, ntree, node, input);
809  add_dummy_decorator = true;
810 
811  if (depth == 0 || !(input->flag & SOCK_COLLAPSED)) {
812  if (depth == 0) {
813  uiItemS(layout);
814  }
815 
816  ui_node_draw_node(layout, C, ntree, lnode, depth);
817  }
818  }
819  else {
820  row = uiLayoutRow(row, true);
821 
822  uiTemplateNodeLink(row, C, ntree, node, input);
823 
824  if (input->flag & SOCK_HIDE_VALUE) {
825  add_dummy_decorator = true;
826  }
827  /* input not linked, show value */
828  else {
829  uiLayout *sub = row;
830 
831  switch (input->type) {
832  case SOCK_VECTOR:
833  if (input->type == SOCK_VECTOR) {
834  uiItemS(row);
835  sub = uiLayoutColumn(row, true);
836  }
838  case SOCK_FLOAT:
839  case SOCK_INT:
840  case SOCK_BOOLEAN:
841  case SOCK_RGBA:
842  uiItemR(sub, &inputptr, "default_value", 0, "", ICON_NONE);
844  split_wrapper.decorate_column, &inputptr, "default_value", RNA_NO_INDEX);
845  break;
846  case SOCK_STRING: {
847  const bNodeTree *node_tree = (const bNodeTree *)nodeptr.owner_id;
848  if (node_tree->type == NTREE_GEOMETRY) {
850  }
851  else {
852  uiItemR(sub, &inputptr, "default_value", 0, "", ICON_NONE);
853  }
855  split_wrapper.decorate_column, &inputptr, "default_value", RNA_NO_INDEX);
856  break;
857  }
858  default:
859  add_dummy_decorator = true;
860  }
861  }
862  }
863 
864  if (add_dummy_decorator) {
865  uiItemDecoratorR(split_wrapper.decorate_column, NULL, NULL, 0);
866  }
867 
868  /* clear */
869  node->flag &= ~NODE_TEST;
870 }
871 
873  uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *input)
874 {
875  bNode *tnode;
876 
877  if (!ntree) {
878  return;
879  }
880 
881  /* clear for cycle check */
882  for (tnode = ntree->nodes.first; tnode; tnode = tnode->next) {
883  tnode->flag &= ~NODE_TEST;
884  }
885 
886  if (input) {
887  ui_node_draw_input(layout, C, ntree, node, input, 0);
888  }
889  else {
890  ui_node_draw_node(layout, C, ntree, node, 0);
891  }
892 }
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1034
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1018
void id_us_plus(struct ID *id)
Definition: lib_id.c:288
#define NODE_TYPES_BEGIN(ntype)
Definition: BKE_node.h:535
bool nodeGroupPoll(struct bNodeTree *nodetree, struct bNodeTree *grouptree, const char **r_disabled_hint)
Definition: node_common.c:96
#define NODE_CUSTOM_GROUP
Definition: BKE_node.h:876
void nodeUpdate(struct bNodeTree *ntree, struct bNode *node)
Definition: node.cc:4326
void nodeRemLink(struct bNodeTree *ntree, struct bNodeLink *link)
Definition: node.cc:2231
void nodeRemoveNode(struct Main *bmain, struct bNodeTree *ntree, struct bNode *node, bool do_id_user)
Definition: node.cc:2932
void nodeLabel(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen)
Definition: node.cc:4391
void ntreeUpdateTree(struct Main *main, struct bNodeTree *ntree)
Definition: node.cc:4262
int nodeSocketLinkLimit(const struct bNodeSocket *sock)
void nodePositionRelative(struct bNode *from_node, struct bNode *to_node, struct bNodeSocket *from_sock, struct bNodeSocket *to_sock)
Definition: node.cc:2476
struct bNodeLink * nodeAddLink(struct bNodeTree *ntree, struct bNode *fromnode, struct bNodeSocket *fromsock, struct bNode *tonode, struct bNodeSocket *tosock)
Definition: node.cc:2189
#define NODE_CLASS_LAYOUT
Definition: BKE_node.h:361
struct bNode * nodeAddStaticNode(const struct bContext *C, struct bNodeTree *ntree, int type)
Definition: node.cc:2004
#define NODE_CLASS_GROUP
Definition: BKE_node.h:339
int nodeCountSocketLinks(const struct bNodeTree *ntree, const struct bNodeSocket *sock)
#define NODE_TYPES_END
Definition: BKE_node.h:542
#define NODE_CLASS_TEXTURE
Definition: BKE_node.h:346
void nodeSetActive(struct bNodeTree *ntree, struct bNode *node)
Definition: node.cc:3694
A (mainly) macro array library.
#define BLI_array_append(arr, item)
Definition: BLI_array.h:104
#define BLI_array_declare(arr)
Definition: BLI_array.h:62
#define BLI_array_len(arr)
Definition: BLI_array.h:74
#define BLI_array_free(arr)
Definition: BLI_array.h:116
#define ATTR_FALLTHROUGH
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:124
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
int BLI_strcasecmp_natural(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: string.c:766
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy) ATTR_NONNULL()
Definition: string.c:108
#define POINTER_FROM_INT(i)
#define UNUSED(x)
#define POINTER_AS_INT(i)
#define ELEM(...)
#define STREQ(a, b)
#define TIP_(msgid)
#define IFACE_(msgid)
#define N_(msgid)
#define NODE_TEST
#define NTREE_GEOMETRY
#define NODE_ACTIVE_TEXTURE
@ SOCK_OUT
@ SOCK_IN
@ SOCK_HIDE_VALUE
@ SOCK_COLLAPSED
@ SOCK_UNAVAIL
@ SOCK_INT
@ SOCK_VECTOR
@ SOCK_BOOLEAN
@ SOCK_SHADER
@ SOCK_FLOAT
@ SOCK_STRING
@ SOCK_RGBA
void ED_node_tag_update_nodetree(struct Main *bmain, struct bNodeTree *ntree, struct bNode *node)
Definition: node_draw.cc:164
void ED_undo_push(struct bContext *C, const char *str)
Definition: ed_undo.c:117
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
Read Guarded memory(de)allocation.
NODE_GROUP
StructRNA RNA_Node
StructRNA RNA_NodeSocket
#define C
Definition: RandGen.cpp:39
uiBut * uiDefIconTextBut(uiBlock *block, int type, int retval, int icon, const char *str, int x, int y, short width, short height, void *poin, float min, float max, float a1, float a2, const char *tip)
Definition: interface.c:5603
#define UI_UNIT_Y
@ UI_ITEM_R_ICON_ONLY
uiBlock * uiLayoutGetBlock(uiLayout *layout)
@ UI_BUT_ICON_LEFT
Definition: UI_interface.h:260
@ UI_BUT_TEXT_LEFT
Definition: UI_interface.h:259
@ UI_EMBOSS_NONE
Definition: UI_interface.h:108
@ UI_EMBOSS
Definition: UI_interface.h:107
@ UI_BUT_NODE_ACTIVE
Definition: UI_interface.h:196
void UI_but_node_link_set(uiBut *but, struct bNodeSocket *socket, const float draw_color[4])
Definition: interface.c:6820
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
uiBut * uiDefBut(uiBlock *block, int type, int retval, const char *str, int x, int y, short width, short height, void *poin, float min, float max, float a1, float a2, const char *tip)
Definition: interface.c:4687
uiPropertySplitWrapper uiItemPropertySplitWrapperCreate(uiLayout *parent_layout)
void uiItemL(uiLayout *layout, const char *name, int icon)
void UI_but_drawflag_enable(uiBut *but, int flag)
Definition: interface.c:6092
void uiLayoutSetAlignment(uiLayout *layout, char alignment)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
void uiItemS(uiLayout *layout)
uiLayout * uiLayoutRow(uiLayout *layout, bool align)
@ UI_LAYOUT_ALIGN_RIGHT
void UI_but_type_set_menu_from_pulldown(uiBut *but)
Definition: interface.c:6114
void UI_block_emboss_set(uiBlock *block, eUIEmbossType emboss)
Definition: interface.c:3542
@ UI_BLOCK_IS_FLIP
Definition: UI_interface.h:141
@ UI_BLOCK_NO_FLIP
Definition: UI_interface.h:142
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
uiBut * uiDefIconMenuBut(uiBlock *block, uiMenuCreateFunc func, void *arg, int icon, int x, int y, short width, short height, const char *tip)
Definition: interface.c:6435
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
uiLayout * uiLayoutSplit(uiLayout *layout, float percentage, bool align)
uiBut * uiDefMenuBut(uiBlock *block, uiMenuCreateFunc func, void *arg, const char *str, int x, int y, short width, short height, const char *tip)
Definition: interface.c:6393
void uiItemDecoratorR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int index)
void UI_block_layout_set_current(uiBlock *block, uiLayout *layout)
void UI_but_funcN_set(uiBut *but, uiButHandleNFunc funcN, void *argN, void *arg2)
Definition: interface.c:6301
#define UI_UNIT_X
void UI_block_flag_enable(uiBlock *block, int flag)
Definition: interface.c:6067
@ UI_BTYPE_BUT
Definition: UI_interface.h:334
@ UI_BTYPE_LABEL
Definition: UI_interface.h:358
#define UI_MAX_NAME_STR
Definition: UI_interface.h:91
OperationNode * node
Scene scene
bNodeTree * ntree
#define RNA_NO_INDEX
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_dupallocN)(const void *vmemh)
Definition: mallocn.c:42
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
static ulong * next
static unsigned a[3]
Definition: RandGen.cpp:92
void split(const std::string &s, const char delim, std::vector< std::string > &tokens)
Definition: abc_util.cc:115
void node_socket_color_get(bContext *C, bNodeTree *ntree, PointerRNA *node_ptr, bNodeSocket *sock, float r_color[4])
Definition: node_draw.cc:810
void node_geometry_add_attribute_search_button(const bContext *C, const bNodeTree *node_tree, const bNode *node, PointerRNA *socket_ptr, uiLayout *layout)
void node_socket_copy_default_value(bNodeSocket *to, const bNodeSocket *from)
Definition: node_socket.cc:302
static void ui_node_link(bContext *C, void *arg_p, void *event_p)
static void node_socket_add_replace(const bContext *C, bNodeTree *ntree, bNode *node_to, bNodeSocket *sock_to, int type, NodeLinkItem *item)
#define UI_NODE_LINK_DISCONNECT
void uiTemplateNodeView(uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *input)
static void ui_template_node_link_menu(bContext *C, uiLayout *layout, void *but_p)
static void ui_node_sock_name(bNodeTree *ntree, bNodeSocket *sock, char name[UI_MAX_NAME_STR])
void uiTemplateNodeLink(uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *input)
static int ui_node_item_name_compare(const void *a, const void *b)
static int ui_compatible_sockets(int typeA, int typeB)
static void ui_node_link_items(NodeLinkArg *arg, int in_out, NodeLinkItem **r_items, int *r_totitems)
static bool ui_node_item_special_poll(const bNodeTree *UNUSED(ntree), const bNodeType *ntype)
static void node_socket_remove(Main *bmain, bNodeTree *ntree, bNode *node_to, bNodeSocket *sock_to)
struct NodeLinkItem NodeLinkItem
static void node_tag_recursive(bNode *node)
static void node_menu_column_foreach_cb(void *calldata, int nclass, const char *name)
static bool node_link_item_compare(bNode *node, NodeLinkItem *item)
static void node_clear_recursive(bNode *node)
static void ui_node_draw_input(uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *input, int depth)
static void ui_node_draw_node(uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, int depth)
static void node_socket_disconnect(Main *bmain, bNodeTree *ntree, bNode *node_to, bNodeSocket *sock_to)
static void ui_node_menu_column(NodeLinkArg *arg, int nclass, const char *cname)
static void node_remove_linked(Main *bmain, bNodeTree *ntree, bNode *rem_node)
struct NodeLinkArg NodeLinkArg
#define UI_NODE_LINK_REMOVE
static void node_link_item_apply(Main *bmain, bNode *node, NodeLinkItem *item)
void RNA_pointer_create(ID *id, StructRNA *type, void *data, PointerRNA *r_ptr)
Definition: rna_access.c:146
Definition: DNA_ID.h:273
void * next
Definition: DNA_ID.h:274
char name[66]
Definition: DNA_ID.h:283
void * last
Definition: DNA_listBase.h:47
void * first
Definition: DNA_listBase.h:47
Definition: BKE_main.h:116
ListBase nodetrees
Definition: BKE_main.h:170
uiLayout * layout
bNodeSocket * sock
bNodeTree * ntree
NodeLinkItem item
bNodeType * node_type
bNodeTree * ngroup
const char * node_name
const char * socket_name
struct ID * owner_id
Definition: RNA_types.h:50
Compact definition of a node socket.
Definition: BKE_node.h:95
char name[64]
struct bNodeLink * link
struct bNodeSocket * next
struct bNodeSocketType * typeinfo
struct bNodeTreeType * typeinfo
ListBase nodes
ListBase inputs
ListBase outputs
Defines a node type.
Definition: BKE_node.h:221
char ui_name[64]
Definition: BKE_node.h:227
int type
Definition: BKE_node.h:225
bNodeSocketTemplate * outputs
Definition: BKE_node.h:236
short nclass
Definition: BKE_node.h:233
void(* draw_buttons_ex)(struct uiLayout *, struct bContext *C, struct PointerRNA *ptr)
Definition: BKE_node.h:255
void(* draw_buttons)(struct uiLayout *, struct bContext *C, struct PointerRNA *ptr)
Definition: BKE_node.h:253
bNodeSocketTemplate * inputs
Definition: BKE_node.h:236
char idname[64]
Definition: BKE_node.h:224
float locy
ListBase inputs
struct bNodeType * typeinfo
float locx
short type
struct bNode * next
void * storage
float offsetx
ListBase outputs
float offsety
ListBase buttons
char * poin
void * func_argN