Merge branch 'blender-v2.81-release'
[blender.git] / source / blender / editors / space_node / node_templates.c
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
17 /** \file
18  * \ingroup edinterface
19  */
20
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_library.h"
37 #include "BKE_main.h"
38 #include "BKE_scene.h"
39
40 #include "RNA_access.h"
41
42 #include "NOD_socket.h"
43
44 #include "UI_interface.h"
45 #include "../interface/interface_intern.h" /* XXX bad level */
46
47 #include "ED_node.h" /* own include */
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 */
62 } NodeLinkItem;
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  */
68 static bool node_link_item_compare(bNode *node, NodeLinkItem *item)
69 {
70   if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) {
71     return (node->id == (ID *)item->ngroup);
72   }
73   else {
74     return true;
75   }
76 }
77
78 static void node_link_item_apply(Main *bmain, bNode *node, NodeLinkItem *item)
79 {
80   if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) {
81     node->id = (ID *)item->ngroup;
82     ntreeUpdateTree(bmain, item->ngroup);
83   }
84   else {
85     /* nothing to do for now */
86   }
87
88   if (node->id) {
89     id_us_plus(node->id);
90   }
91 }
92
93 static void node_tag_recursive(bNode *node)
94 {
95   bNodeSocket *input;
96
97   if (!node || (node->flag & NODE_TEST)) {
98     return; /* in case of cycles */
99   }
100
101   node->flag |= NODE_TEST;
102
103   for (input = node->inputs.first; input; input = input->next) {
104     if (input->link) {
105       node_tag_recursive(input->link->fromnode);
106     }
107   }
108 }
109
110 static void node_clear_recursive(bNode *node)
111 {
112   bNodeSocket *input;
113
114   if (!node || !(node->flag & NODE_TEST)) {
115     return; /* in case of cycles */
116   }
117
118   node->flag &= ~NODE_TEST;
119
120   for (input = node->inputs.first; input; input = input->next) {
121     if (input->link) {
122       node_clear_recursive(input->link->fromnode);
123     }
124   }
125 }
126
127 static void node_remove_linked(Main *bmain, bNodeTree *ntree, bNode *rem_node)
128 {
129   bNode *node, *next;
130   bNodeSocket *sock;
131
132   if (!rem_node) {
133     return;
134   }
135
136   /* tag linked nodes to be removed */
137   for (node = ntree->nodes.first; node; node = node->next) {
138     node->flag &= ~NODE_TEST;
139   }
140
141   node_tag_recursive(rem_node);
142
143   /* clear tags on nodes that are still used by other nodes */
144   for (node = ntree->nodes.first; node; node = node->next) {
145     if (!(node->flag & NODE_TEST)) {
146       for (sock = node->inputs.first; sock; sock = sock->next) {
147         if (sock->link && sock->link->fromnode != rem_node) {
148           node_clear_recursive(sock->link->fromnode);
149         }
150       }
151     }
152   }
153
154   /* remove nodes */
155   for (node = ntree->nodes.first; node; node = next) {
156     next = node->next;
157
158     if (node->flag & NODE_TEST) {
159       nodeRemoveNode(bmain, ntree, node, true);
160     }
161   }
162 }
163
164 /* disconnect socket from the node it is connected to */
165 static void node_socket_disconnect(Main *bmain,
166                                    bNodeTree *ntree,
167                                    bNode *node_to,
168                                    bNodeSocket *sock_to)
169 {
170   if (!sock_to->link) {
171     return;
172   }
173
174   nodeRemLink(ntree, sock_to->link);
175   sock_to->flag |= SOCK_COLLAPSED;
176
177   nodeUpdate(ntree, node_to);
178   ntreeUpdateTree(bmain, ntree);
179
180   ED_node_tag_update_nodetree(bmain, ntree, node_to);
181 }
182
183 /* remove all nodes connected to this socket, if they aren't connected to other nodes */
184 static void node_socket_remove(Main *bmain, bNodeTree *ntree, bNode *node_to, bNodeSocket *sock_to)
185 {
186   if (!sock_to->link) {
187     return;
188   }
189
190   node_remove_linked(bmain, ntree, sock_to->link->fromnode);
191   sock_to->flag |= SOCK_COLLAPSED;
192
193   nodeUpdate(ntree, node_to);
194   ntreeUpdateTree(bmain, ntree);
195
196   ED_node_tag_update_nodetree(bmain, ntree, node_to);
197 }
198
199 /* add new node connected to this socket, or replace an existing one */
200 static void node_socket_add_replace(const bContext *C,
201                                     bNodeTree *ntree,
202                                     bNode *node_to,
203                                     bNodeSocket *sock_to,
204                                     int type,
205                                     NodeLinkItem *item)
206 {
207   Main *bmain = CTX_data_main(C);
208   bNode *node_from;
209   bNodeSocket *sock_from_tmp;
210   bNode *node_prev = NULL;
211
212   /* unlink existing node */
213   if (sock_to->link) {
214     node_prev = sock_to->link->fromnode;
215     nodeRemLink(ntree, sock_to->link);
216   }
217
218   /* find existing node that we can use */
219   for (node_from = ntree->nodes.first; node_from; node_from = node_from->next) {
220     if (node_from->type == type) {
221       break;
222     }
223   }
224
225   if (node_from) {
226     if (node_from->inputs.first || node_from->typeinfo->draw_buttons ||
227         node_from->typeinfo->draw_buttons_ex) {
228       node_from = NULL;
229     }
230   }
231
232   if (node_prev && node_prev->type == type && node_link_item_compare(node_prev, item)) {
233     /* keep the previous node if it's the same type */
234     node_from = node_prev;
235   }
236   else if (!node_from) {
237     node_from = nodeAddStaticNode(C, ntree, type);
238     if (node_prev != NULL) {
239       /* If we're replacing existing node, use its location. */
240       node_from->locx = node_prev->locx;
241       node_from->locy = node_prev->locy;
242       node_from->offsetx = node_prev->offsetx;
243       node_from->offsety = node_prev->offsety;
244     }
245     else {
246       sock_from_tmp = BLI_findlink(&node_from->outputs, item->socket_index);
247       nodePositionRelative(node_from, node_to, sock_from_tmp, sock_to);
248     }
249
250     node_link_item_apply(bmain, node_from, item);
251   }
252
253   nodeSetActive(ntree, node_from);
254
255   /* add link */
256   sock_from_tmp = BLI_findlink(&node_from->outputs, item->socket_index);
257   nodeAddLink(ntree, node_from, sock_from_tmp, node_to, sock_to);
258   sock_to->flag &= ~SOCK_COLLAPSED;
259
260   /* copy input sockets from previous node */
261   if (node_prev && node_from != node_prev) {
262     bNodeSocket *sock_prev, *sock_from;
263
264     for (sock_prev = node_prev->inputs.first; sock_prev; sock_prev = sock_prev->next) {
265       for (sock_from = node_from->inputs.first; sock_from; sock_from = sock_from->next) {
266         if (nodeCountSocketLinks(ntree, sock_from) >= sock_from->limit) {
267           continue;
268         }
269
270         if (STREQ(sock_prev->name, sock_from->name) && sock_prev->type == sock_from->type) {
271           bNodeLink *link = sock_prev->link;
272
273           if (link && link->fromnode) {
274             nodeAddLink(ntree, link->fromnode, link->fromsock, node_from, sock_from);
275             nodeRemLink(ntree, link);
276           }
277
278           node_socket_copy_default_value(sock_from, sock_prev);
279         }
280       }
281     }
282
283     /* also preserve mapping for texture nodes */
284     if (node_from->typeinfo->nclass == NODE_CLASS_TEXTURE &&
285         node_prev->typeinfo->nclass == NODE_CLASS_TEXTURE) {
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);
295   ntreeUpdateTree(CTX_data_main(C), ntree);
296
297   ED_node_tag_update_nodetree(CTX_data_main(C), ntree, node_to);
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 {
307   Main *bmain;
308   Scene *scene;
309   bNodeTree *ntree;
310   bNode *node;
311   bNodeSocket *sock;
312
313   bNodeType *node_type;
314   NodeLinkItem item;
315
316   uiLayout *layout;
317 } NodeLinkArg;
318
319 static void ui_node_link_items(NodeLinkArg *arg,
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       ListBase *lb = ((in_out == SOCK_IN) ? &ngroup->inputs : &ngroup->outputs);
334       totitems += BLI_listbase_count(lb);
335     }
336
337     if (totitems > 0) {
338       items = MEM_callocN(sizeof(NodeLinkItem) * totitems, "ui node link items");
339
340       i = 0;
341       for (ngroup = arg->bmain->nodetrees.first; ngroup; ngroup = ngroup->id.next) {
342         ListBase *lb = (in_out == SOCK_IN ? &ngroup->inputs : &ngroup->outputs);
343         bNodeSocket *stemp;
344         int index;
345         for (stemp = lb->first, index = 0; stemp; stemp = stemp->next, index++, i++) {
346           NodeLinkItem *item = &items[i];
347
348           item->socket_index = index;
349           /* note: int stemp->type is not fully reliable, not used for node group
350            * interface sockets. use the typeinfo->type instead.
351            */
352           item->socket_type = stemp->typeinfo->type;
353           item->socket_name = stemp->name;
354           item->node_name = ngroup->id.name + 2;
355           item->ngroup = ngroup;
356         }
357       }
358     }
359   }
360   else {
361     bNodeSocketTemplate *socket_templates = (in_out == SOCK_IN ? arg->node_type->inputs :
362                                                                  arg->node_type->outputs);
363     bNodeSocketTemplate *stemp;
364     int i;
365
366     for (stemp = socket_templates; stemp && stemp->type != -1; stemp++) {
367       totitems++;
368     }
369
370     if (totitems > 0) {
371       items = MEM_callocN(sizeof(NodeLinkItem) * totitems, "ui node link items");
372
373       i = 0;
374       for (stemp = socket_templates; stemp && stemp->type != -1; stemp++, i++) {
375         NodeLinkItem *item = &items[i];
376
377         item->socket_index = i;
378         item->socket_type = stemp->type;
379         item->socket_name = stemp->name;
380         item->node_name = arg->node_type->ui_name;
381       }
382     }
383   }
384
385   *r_items = items;
386   *r_totitems = totitems;
387 }
388
389 static void ui_node_link(bContext *C, void *arg_p, void *event_p)
390 {
391   NodeLinkArg *arg = (NodeLinkArg *)arg_p;
392   Main *bmain = arg->bmain;
393   bNode *node_to = arg->node;
394   bNodeSocket *sock_to = arg->sock;
395   bNodeTree *ntree = arg->ntree;
396   int event = POINTER_AS_INT(event_p);
397
398   if (event == UI_NODE_LINK_DISCONNECT) {
399     node_socket_disconnect(bmain, ntree, node_to, sock_to);
400   }
401   else if (event == UI_NODE_LINK_REMOVE) {
402     node_socket_remove(bmain, ntree, node_to, sock_to);
403   }
404   else {
405     node_socket_add_replace(C, ntree, node_to, sock_to, arg->node_type->type, &arg->item);
406   }
407
408   ED_undo_push(C, "Node input modify");
409 }
410
411 static void ui_node_sock_name(bNodeTree *ntree, bNodeSocket *sock, char name[UI_MAX_NAME_STR])
412 {
413   if (sock->link && sock->link->fromnode) {
414     bNode *node = sock->link->fromnode;
415     char node_name[UI_MAX_NAME_STR];
416
417     nodeLabel(ntree, node, node_name, sizeof(node_name));
418
419     if (BLI_listbase_is_empty(&node->inputs) && node->outputs.first != node->outputs.last) {
420       BLI_snprintf(
421           name, UI_MAX_NAME_STR, "%s | %s", IFACE_(node_name), IFACE_(sock->link->fromsock->name));
422     }
423     else {
424       BLI_strncpy(name, IFACE_(node_name), UI_MAX_NAME_STR);
425     }
426   }
427   else if (sock->type == SOCK_SHADER) {
428     BLI_strncpy(name, IFACE_("None"), UI_MAX_NAME_STR);
429   }
430   else {
431     BLI_strncpy(name, IFACE_("Default"), UI_MAX_NAME_STR);
432   }
433 }
434
435 static int ui_compatible_sockets(int typeA, int typeB)
436 {
437   return (typeA == typeB);
438 }
439
440 static int ui_node_item_name_compare(const void *a, const void *b)
441 {
442   const bNodeType *type_a = *(const bNodeType **)a;
443   const bNodeType *type_b = *(const bNodeType **)b;
444   return BLI_strcasecmp_natural(type_a->ui_name, type_b->ui_name);
445 }
446
447 static bool ui_node_item_special_poll(const bNodeTree *UNUSED(ntree), const bNodeType *ntype)
448 {
449   if (STREQ(ntype->idname, "ShaderNodeUVAlongStroke")) {
450     /* TODO(sergey): Currently we don't have Freestyle nodes edited from
451      * the buttons context, so can ignore it's nodes completely.
452      *
453      * However, we might want to do some extra checks here later.
454      */
455     return false;
456   }
457   return true;
458 }
459
460 static void ui_node_menu_column(NodeLinkArg *arg, int nclass, const char *cname)
461 {
462   bNodeTree *ntree = arg->ntree;
463   bNodeSocket *sock = arg->sock;
464   uiLayout *layout = arg->layout;
465   uiLayout *column = NULL;
466   uiBlock *block = uiLayoutGetBlock(layout);
467   uiBut *but;
468   NodeLinkArg *argN;
469   int first = 1;
470
471   /* generate array of node types sorted by UI name */
472   bNodeType **sorted_ntypes = NULL;
473   BLI_array_declare(sorted_ntypes);
474
475   NODE_TYPES_BEGIN (ntype) {
476     if (!(ntype->poll && ntype->poll(ntype, ntree))) {
477       continue;
478     }
479
480     if (ntype->nclass != nclass) {
481       continue;
482     }
483
484     if (!ui_node_item_special_poll(ntree, ntype)) {
485       continue;
486     }
487
488     BLI_array_append(sorted_ntypes, ntype);
489   }
490   NODE_TYPES_END;
491
492   qsort(
493       sorted_ntypes, BLI_array_len(sorted_ntypes), sizeof(bNodeType *), ui_node_item_name_compare);
494
495   /* generate UI */
496   for (int j = 0; j < BLI_array_len(sorted_ntypes); j++) {
497     bNodeType *ntype = sorted_ntypes[j];
498     NodeLinkItem *items;
499     int totitems;
500     char name[UI_MAX_NAME_STR];
501     const char *cur_node_name = NULL;
502     int i, num = 0;
503     int icon = ICON_NONE;
504
505     arg->node_type = ntype;
506
507     ui_node_link_items(arg, SOCK_OUT, &items, &totitems);
508
509     for (i = 0; i < totitems; i++) {
510       if (ui_compatible_sockets(items[i].socket_type, sock->type)) {
511         num++;
512       }
513     }
514
515     for (i = 0; i < totitems; i++) {
516       if (!ui_compatible_sockets(items[i].socket_type, sock->type)) {
517         continue;
518       }
519
520       if (first) {
521         column = uiLayoutColumn(layout, 0);
522         UI_block_layout_set_current(block, column);
523
524         uiItemL(column, IFACE_(cname), ICON_NODE);
525         but = block->buttons.last;
526
527         first = 0;
528       }
529
530       if (num > 1) {
531         if (!cur_node_name || !STREQ(cur_node_name, items[i].node_name)) {
532           cur_node_name = items[i].node_name;
533           /* XXX Do not use uiItemL here,
534            * it would add an empty icon as we are in a menu! */
535           uiDefBut(block,
536                    UI_BTYPE_LABEL,
537                    0,
538                    IFACE_(cur_node_name),
539                    0,
540                    0,
541                    UI_UNIT_X * 4,
542                    UI_UNIT_Y,
543                    NULL,
544                    0.0,
545                    0.0,
546                    0.0,
547                    0.0,
548                    "");
549         }
550
551         BLI_snprintf(name, UI_MAX_NAME_STR, "%s", IFACE_(items[i].socket_name));
552         icon = ICON_BLANK1;
553       }
554       else {
555         BLI_strncpy(name, IFACE_(items[i].node_name), UI_MAX_NAME_STR);
556         icon = ICON_NONE;
557       }
558
559       but = uiDefIconTextBut(block,
560                              UI_BTYPE_BUT,
561                              0,
562                              icon,
563                              name,
564                              0,
565                              0,
566                              UI_UNIT_X * 4,
567                              UI_UNIT_Y,
568                              NULL,
569                              0.0,
570                              0.0,
571                              0.0,
572                              0.0,
573                              TIP_("Add node to input"));
574
575       argN = MEM_dupallocN(arg);
576       argN->item = items[i];
577       UI_but_funcN_set(but, ui_node_link, argN, NULL);
578     }
579
580     if (items) {
581       MEM_freeN(items);
582     }
583   }
584
585   BLI_array_free(sorted_ntypes);
586 }
587
588 static void node_menu_column_foreach_cb(void *calldata, int nclass, const char *name)
589 {
590   NodeLinkArg *arg = (NodeLinkArg *)calldata;
591
592   if (!ELEM(nclass, NODE_CLASS_GROUP, NODE_CLASS_LAYOUT)) {
593     ui_node_menu_column(arg, nclass, name);
594   }
595 }
596
597 static void ui_template_node_link_menu(bContext *C, uiLayout *layout, void *but_p)
598 {
599   Main *bmain = CTX_data_main(C);
600   Scene *scene = CTX_data_scene(C);
601   uiBlock *block = uiLayoutGetBlock(layout);
602   uiBut *but = (uiBut *)but_p;
603   uiLayout *split, *column;
604   NodeLinkArg *arg = (NodeLinkArg *)but->func_argN;
605   bNodeSocket *sock = arg->sock;
606   bNodeTreeType *ntreetype = arg->ntree->typeinfo;
607
608   UI_block_flag_enable(block, UI_BLOCK_NO_FLIP | UI_BLOCK_IS_FLIP);
609   UI_block_layout_set_current(block, layout);
610   split = uiLayoutSplit(layout, 0.0f, false);
611
612   arg->bmain = bmain;
613   arg->scene = scene;
614   arg->layout = split;
615
616   if (ntreetype && ntreetype->foreach_nodeclass) {
617     ntreetype->foreach_nodeclass(scene, arg, node_menu_column_foreach_cb);
618   }
619
620   column = uiLayoutColumn(split, false);
621   UI_block_layout_set_current(block, column);
622
623   if (sock->link) {
624     uiItemL(column, IFACE_("Link"), ICON_NONE);
625     but = block->buttons.last;
626     but->drawflag = UI_BUT_TEXT_LEFT;
627
628     but = uiDefBut(block,
629                    UI_BTYPE_BUT,
630                    0,
631                    IFACE_("Remove"),
632                    0,
633                    0,
634                    UI_UNIT_X * 4,
635                    UI_UNIT_Y,
636                    NULL,
637                    0.0,
638                    0.0,
639                    0.0,
640                    0.0,
641                    TIP_("Remove nodes connected to the input"));
642     UI_but_funcN_set(but, ui_node_link, MEM_dupallocN(arg), POINTER_FROM_INT(UI_NODE_LINK_REMOVE));
643
644     but = uiDefBut(block,
645                    UI_BTYPE_BUT,
646                    0,
647                    IFACE_("Disconnect"),
648                    0,
649                    0,
650                    UI_UNIT_X * 4,
651                    UI_UNIT_Y,
652                    NULL,
653                    0.0,
654                    0.0,
655                    0.0,
656                    0.0,
657                    TIP_("Disconnect nodes connected to the input"));
658     UI_but_funcN_set(
659         but, ui_node_link, MEM_dupallocN(arg), POINTER_FROM_INT(UI_NODE_LINK_DISCONNECT));
660   }
661
662   ui_node_menu_column(arg, NODE_CLASS_GROUP, N_("Group"));
663 }
664
665 void uiTemplateNodeLink(uiLayout *layout, bNodeTree *ntree, bNode *node, bNodeSocket *sock)
666 {
667   uiBlock *block = uiLayoutGetBlock(layout);
668   NodeLinkArg *arg;
669   uiBut *but;
670
671   arg = MEM_callocN(sizeof(NodeLinkArg), "NodeLinkArg");
672   arg->ntree = ntree;
673   arg->node = node;
674   arg->sock = sock;
675
676   UI_block_layout_set_current(block, layout);
677
678   if (sock->link || sock->type == SOCK_SHADER || (sock->flag & SOCK_HIDE_VALUE)) {
679     char name[UI_MAX_NAME_STR];
680     ui_node_sock_name(ntree, sock, name);
681     but = uiDefMenuBut(
682         block, ui_template_node_link_menu, NULL, name, 0, 0, UI_UNIT_X * 4, UI_UNIT_Y, "");
683   }
684   else {
685     but = uiDefIconMenuBut(
686         block, ui_template_node_link_menu, NULL, ICON_NONE, 0, 0, UI_UNIT_X, UI_UNIT_Y, "");
687   }
688
689   UI_but_type_set_menu_from_pulldown(but);
690
691   but->flag |= UI_BUT_NODE_LINK;
692   but->poin = (char *)but;
693   but->func_argN = arg;
694
695   if (sock->link && sock->link->fromnode) {
696     if (sock->link->fromnode->flag & NODE_ACTIVE_TEXTURE) {
697       but->flag |= UI_BUT_NODE_ACTIVE;
698     }
699   }
700 }
701
702 /**************************** Node Tree Layout *******************************/
703
704 static void ui_node_draw_input(
705     uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *input, int depth);
706
707 static void ui_node_draw_node(
708     uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, int depth)
709 {
710   bNodeSocket *input;
711   uiLayout *col, *split;
712   PointerRNA nodeptr;
713
714   RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr);
715
716   if (node->typeinfo->draw_buttons) {
717     if (node->type != NODE_GROUP) {
718       split = uiLayoutSplit(layout, 0.5f, false);
719       col = uiLayoutColumn(split, false);
720       col = uiLayoutColumn(split, false);
721
722       node->typeinfo->draw_buttons(col, C, &nodeptr);
723     }
724   }
725
726   for (input = node->inputs.first; input; input = input->next) {
727     ui_node_draw_input(layout, C, ntree, node, input, depth + 1);
728   }
729 }
730
731 static void ui_node_draw_input(
732     uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *input, int depth)
733 {
734   PointerRNA inputptr, nodeptr;
735   uiBlock *block = uiLayoutGetBlock(layout);
736   uiBut *bt;
737   uiLayout *split, *row, *col;
738   bNode *lnode;
739   char label[UI_MAX_NAME_STR];
740   int i, indent = (depth > 1) ? 2 * (depth - 1) : 0;
741   int dependency_loop;
742
743   if (input->flag & SOCK_UNAVAIL) {
744     return;
745   }
746
747   /* to avoid eternal loops on cyclic dependencies */
748   node->flag |= NODE_TEST;
749   lnode = (input->link) ? input->link->fromnode : NULL;
750
751   dependency_loop = (lnode && (lnode->flag & NODE_TEST));
752   if (dependency_loop) {
753     lnode = NULL;
754   }
755
756   /* socket RNA pointer */
757   RNA_pointer_create(&ntree->id, &RNA_NodeSocket, input, &inputptr);
758   RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr);
759
760   /* indented label */
761   for (i = 0; i < indent; i++) {
762     label[i] = ' ';
763   }
764   label[indent] = '\0';
765   BLI_snprintf(label + indent, UI_MAX_NAME_STR - indent, "%s", IFACE_(input->name));
766
767   /* split in label and value */
768   split = uiLayoutSplit(layout, 0.5f, false);
769
770   row = uiLayoutRow(split, true);
771
772   if (depth > 0) {
773     UI_block_emboss_set(block, UI_EMBOSS_NONE);
774
775     if (lnode &&
776         (lnode->inputs.first || (lnode->typeinfo->draw_buttons && lnode->type != NODE_GROUP))) {
777       int icon = (input->flag & SOCK_COLLAPSED) ? ICON_DISCLOSURE_TRI_RIGHT :
778                                                   ICON_DISCLOSURE_TRI_DOWN;
779       uiItemR(row, &inputptr, "show_expanded", UI_ITEM_R_ICON_ONLY, "", icon);
780     }
781     else {
782       uiItemL(row, "", ICON_BLANK1);
783     }
784
785     bt = block->buttons.last;
786     bt->rect.xmax = UI_UNIT_X / 2;
787
788     UI_block_emboss_set(block, UI_EMBOSS);
789   }
790
791   uiItemL(row, label, ICON_NONE);
792   bt = block->buttons.last;
793   bt->drawflag = UI_BUT_TEXT_RIGHT;
794
795   if (dependency_loop) {
796     row = uiLayoutRow(split, false);
797     uiItemL(row, IFACE_("Dependency Loop"), ICON_ERROR);
798   }
799   else if (lnode) {
800     /* input linked to a node */
801     uiTemplateNodeLink(split, ntree, node, input);
802
803     if (depth == 0 || !(input->flag & SOCK_COLLAPSED)) {
804       if (depth == 0) {
805         uiItemS(layout);
806       }
807
808       ui_node_draw_node(layout, C, ntree, lnode, depth);
809     }
810   }
811   else {
812     /* input not linked, show value */
813     if (!(input->flag & SOCK_HIDE_VALUE)) {
814       switch (input->type) {
815         case SOCK_FLOAT:
816         case SOCK_INT:
817         case SOCK_BOOLEAN:
818         case SOCK_RGBA:
819         case SOCK_STRING:
820           row = uiLayoutRow(split, true);
821           uiItemR(row, &inputptr, "default_value", 0, "", ICON_NONE);
822           break;
823         case SOCK_VECTOR:
824           row = uiLayoutRow(split, false);
825           col = uiLayoutColumn(row, false);
826           uiItemR(col, &inputptr, "default_value", 0, "", ICON_NONE);
827           break;
828
829         default:
830           row = uiLayoutRow(split, false);
831           break;
832       }
833     }
834     else {
835       row = uiLayoutRow(split, false);
836     }
837
838     uiTemplateNodeLink(row, ntree, node, input);
839   }
840
841   /* clear */
842   node->flag &= ~NODE_TEST;
843 }
844
845 void uiTemplateNodeView(
846     uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *input)
847 {
848   bNode *tnode;
849
850   if (!ntree) {
851     return;
852   }
853
854   /* clear for cycle check */
855   for (tnode = ntree->nodes.first; tnode; tnode = tnode->next) {
856     tnode->flag &= ~NODE_TEST;
857   }
858
859   if (input) {
860     ui_node_draw_input(layout, C, ntree, node, input, 0);
861   }
862   else {
863     ui_node_draw_node(layout, C, ntree, node, 0);
864   }
865 }