Fix linker warning about zero length memset.
[blender.git] / source / blender / editors / space_node / node_templates.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Contributor(s): Blender Foundation 2009.
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 /** \file blender/editors/space_node/node_templates.c
24  *  \ingroup edinterface
25  */
26
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include "MEM_guardedalloc.h"
31
32 #include "DNA_node_types.h"
33 #include "DNA_screen_types.h"
34
35 #include "BLI_listbase.h"
36 #include "BLI_string.h"
37
38 #include "BLT_translation.h"
39
40 #include "BKE_context.h"
41 #include "BKE_global.h"
42 #include "BKE_library.h"
43 #include "BKE_main.h"
44 #include "BKE_scene.h"
45
46 #include "RNA_access.h"
47
48 #include "NOD_socket.h"
49
50 #include "UI_interface.h"
51 #include "../interface/interface_intern.h"  /* XXX bad level */
52
53 #include "ED_node.h"  /* own include */
54
55 #include "ED_util.h"
56
57
58 /************************* Node Socket Manipulation **************************/
59
60 /* describes an instance of a node type and a specific socket to link */
61 typedef struct NodeLinkItem {
62         int socket_index;                       /* index for linking */
63         int socket_type;                        /* socket type for compatibility check */
64         const char *socket_name;        /* ui label of the socket */
65         const char *node_name;          /* ui label of the node */
66         
67         /* extra settings */
68         bNodeTree *ngroup;              /* group node tree */
69 } NodeLinkItem;
70
71 /* Compare an existing node to a link item to see if it can be reused.
72  * item must be for the same node type!
73  * XXX should become a node type callback
74  */
75 static bool node_link_item_compare(bNode *node, NodeLinkItem *item)
76 {
77         if (node->type == NODE_GROUP) {
78                 return (node->id == (ID *)item->ngroup);
79         }
80         else
81                 return true;
82 }
83
84 static void node_link_item_apply(bNode *node, NodeLinkItem *item)
85 {
86         if (node->type == NODE_GROUP) {
87                 node->id = (ID *)item->ngroup;
88                 ntreeUpdateTree(G.main, item->ngroup);
89         }
90         else {
91                 /* nothing to do for now */
92         }
93         
94         if (node->id)
95                 id_us_plus(node->id);
96 }
97
98 static void node_tag_recursive(bNode *node)
99 {
100         bNodeSocket *input;
101
102         if (!node || (node->flag & NODE_TEST))
103                 return;  /* in case of cycles */
104
105         node->flag |= NODE_TEST;
106
107         for (input = node->inputs.first; input; input = input->next)
108                 if (input->link)
109                         node_tag_recursive(input->link->fromnode);
110 }
111
112 static void node_clear_recursive(bNode *node)
113 {
114         bNodeSocket *input;
115
116         if (!node || !(node->flag & NODE_TEST))
117                 return;  /* in case of cycles */
118
119         node->flag &= ~NODE_TEST;
120
121         for (input = node->inputs.first; input; input = input->next)
122                 if (input->link)
123                         node_clear_recursive(input->link->fromnode);
124 }
125
126 static void node_remove_linked(bNodeTree *ntree, bNode *rem_node)
127 {
128         bNode *node, *next;
129         bNodeSocket *sock;
130
131         if (!rem_node)
132                 return;
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         node_tag_recursive(rem_node);
139
140         /* clear tags on nodes that are still used by other nodes */
141         for (node = ntree->nodes.first; node; node = node->next)
142                 if (!(node->flag & NODE_TEST))
143                         for (sock = node->inputs.first; sock; sock = sock->next)
144                                 if (sock->link && sock->link->fromnode != rem_node)
145                                         node_clear_recursive(sock->link->fromnode);
146
147         /* remove nodes */
148         for (node = ntree->nodes.first; node; node = next) {
149                 next = node->next;
150
151                 if (node->flag & NODE_TEST) {
152                         if (node->id)
153                                 node->id->us--;
154                         nodeFreeNode(ntree, node);
155                 }
156         }
157 }
158
159 /* disconnect socket from the node it is connected to */
160 static void node_socket_disconnect(Main *bmain, bNodeTree *ntree, bNode *node_to, bNodeSocket *sock_to)
161 {
162         if (!sock_to->link)
163                 return;
164
165         nodeRemLink(ntree, sock_to->link);
166         sock_to->flag |= SOCK_COLLAPSED;
167
168         nodeUpdate(ntree, node_to);
169         ntreeUpdateTree(bmain, ntree);
170
171         ED_node_tag_update_nodetree(bmain, ntree);
172 }
173
174 /* remove all nodes connected to this socket, if they aren't connected to other nodes */
175 static void node_socket_remove(Main *bmain, bNodeTree *ntree, bNode *node_to, bNodeSocket *sock_to)
176 {
177         if (!sock_to->link)
178                 return;
179
180         node_remove_linked(ntree, sock_to->link->fromnode);
181         sock_to->flag |= SOCK_COLLAPSED;
182
183         nodeUpdate(ntree, node_to);
184         ntreeUpdateTree(bmain, ntree);
185
186         ED_node_tag_update_nodetree(bmain, ntree);
187 }
188
189 /* add new node connected to this socket, or replace an existing one */
190 static void node_socket_add_replace(const bContext *C, bNodeTree *ntree, bNode *node_to, bNodeSocket *sock_to,
191                                     int type, NodeLinkItem *item)
192 {
193         bNode *node_from;
194         bNodeSocket *sock_from_tmp;
195         bNode *node_prev = NULL;
196
197         /* unlink existing node */
198         if (sock_to->link) {
199                 node_prev = sock_to->link->fromnode;
200                 nodeRemLink(ntree, sock_to->link);
201         }
202
203         /* find existing node that we can use */
204         for (node_from = ntree->nodes.first; node_from; node_from = node_from->next)
205                 if (node_from->type == type)
206                         break;
207
208         if (node_from)
209                 if (node_from->inputs.first || node_from->typeinfo->draw_buttons || node_from->typeinfo->draw_buttons_ex)
210                         node_from = NULL;
211
212         if (node_prev && node_prev->type == type && node_link_item_compare(node_prev, item)) {
213                 /* keep the previous node if it's the same type */
214                 node_from = node_prev;
215         }
216         else if (!node_from) {
217                 node_from = nodeAddStaticNode(C, ntree, type);
218                 if (node_prev != NULL) {
219                         /* If we're replacing existing node, use it's location. */
220                         node_from->locx = node_prev->locx;
221                         node_from->locy = node_prev->locy;
222                         node_from->offsetx = node_prev->offsetx;
223                         node_from->offsety = node_prev->offsety;
224                 }
225                 else {
226                         /* Avoid exact intersection of nodes.
227                          * TODO(sergey): Still not ideal, but better than nothing.
228                          */
229                         int index = BLI_findindex(&node_to->inputs, sock_to);
230                         BLI_assert(index != -1);
231                         node_from->locx = node_to->locx - (node_from->typeinfo->width + 50);
232                         node_from->locy = node_to->locy - (node_from->typeinfo->height * index);
233                 }
234                 
235                 node_link_item_apply(node_from, item);
236         }
237
238         nodeSetActive(ntree, node_from);
239
240         /* add link */
241         sock_from_tmp = BLI_findlink(&node_from->outputs, item->socket_index);
242         nodeAddLink(ntree, node_from, sock_from_tmp, node_to, sock_to);
243         sock_to->flag &= ~SOCK_COLLAPSED;
244
245         /* copy input sockets from previous node */
246         if (node_prev && node_from != node_prev) {
247                 bNodeSocket *sock_prev, *sock_from;
248
249                 for (sock_prev = node_prev->inputs.first; sock_prev; sock_prev = sock_prev->next) {
250                         for (sock_from = node_from->inputs.first; sock_from; sock_from = sock_from->next) {
251                                 if (nodeCountSocketLinks(ntree, sock_from) >= sock_from->limit)
252                                         continue;
253
254                                 if (STREQ(sock_prev->name, sock_from->name) && sock_prev->type == sock_from->type) {
255                                         bNodeLink *link = sock_prev->link;
256
257                                         if (link && link->fromnode) {
258                                                 nodeAddLink(ntree, link->fromnode, link->fromsock, node_from, sock_from);
259                                                 nodeRemLink(ntree, link);
260                                         }
261
262                                         node_socket_copy_default_value(sock_from, sock_prev);
263                                 }
264                         }
265                 }
266
267                 /* also preserve mapping for texture nodes */
268                 if (node_from->typeinfo->nclass == NODE_CLASS_TEXTURE &&
269                     node_prev->typeinfo->nclass == NODE_CLASS_TEXTURE)
270                 {
271                         memcpy(node_from->storage, node_prev->storage, sizeof(NodeTexBase));
272                 }
273
274                 /* remove node */
275                 node_remove_linked(ntree, node_prev);
276         }
277
278         nodeUpdate(ntree, node_from);
279         nodeUpdate(ntree, node_to);
280         ntreeUpdateTree(CTX_data_main(C), ntree);
281
282         ED_node_tag_update_nodetree(CTX_data_main(C), ntree);
283 }
284
285 /****************************** Node Link Menu *******************************/
286
287 // #define UI_NODE_LINK_ADD        0
288 #define UI_NODE_LINK_DISCONNECT -1
289 #define UI_NODE_LINK_REMOVE     -2
290
291 typedef struct NodeLinkArg {
292         Main *bmain;
293         Scene *scene;
294         bNodeTree *ntree;
295         bNode *node;
296         bNodeSocket *sock;
297
298         bNodeType *node_type;
299         NodeLinkItem item;
300
301         uiLayout *layout;
302 } NodeLinkArg;
303
304 static void ui_node_link_items(NodeLinkArg *arg, int in_out, NodeLinkItem **r_items, int *r_totitems)
305 {
306         /* XXX this should become a callback for node types! */
307         NodeLinkItem *items = NULL;
308         int totitems = 0;
309         
310         if (arg->node_type->type == NODE_GROUP) {
311                 bNodeTree *ngroup;
312                 int i;
313                 
314                 for (ngroup = arg->bmain->nodetree.first; ngroup; ngroup = ngroup->id.next) {
315                         ListBase *lb = ((in_out == SOCK_IN) ? &ngroup->inputs : &ngroup->outputs);
316                         totitems += BLI_listbase_count(lb);
317                 }
318                 
319                 if (totitems > 0) {
320                         items = MEM_callocN(sizeof(NodeLinkItem) * totitems, "ui node link items");
321                         
322                         i = 0;
323                         for (ngroup = arg->bmain->nodetree.first; ngroup; ngroup = ngroup->id.next) {
324                                 ListBase *lb = (in_out == SOCK_IN ? &ngroup->inputs : &ngroup->outputs);
325                                 bNodeSocket *stemp;
326                                 int index;
327                                 for (stemp = lb->first, index = 0; stemp; stemp = stemp->next, ++index, ++i) {
328                                         NodeLinkItem *item = &items[i];
329                                         
330                                         item->socket_index = index;
331                                         /* note: int stemp->type is not fully reliable, not used for node group
332                                          * interface sockets. use the typeinfo->type instead.
333                                          */
334                                         item->socket_type = stemp->typeinfo->type;
335                                         item->socket_name = stemp->name;
336                                         item->node_name = ngroup->id.name + 2;
337                                         item->ngroup = ngroup;
338                                 }
339                         }
340                 }
341         }
342         else {
343                 bNodeSocketTemplate *socket_templates = (in_out == SOCK_IN ? arg->node_type->inputs : arg->node_type->outputs);
344                 bNodeSocketTemplate *stemp;
345                 int i;
346                 
347                 for (stemp = socket_templates; stemp && stemp->type != -1; ++stemp)
348                         ++totitems;
349                 
350                 if (totitems > 0) {
351                         items = MEM_callocN(sizeof(NodeLinkItem) * totitems, "ui node link items");
352                         
353                         i = 0;
354                         for (stemp = socket_templates; stemp && stemp->type != -1; ++stemp, ++i) {
355                                 NodeLinkItem *item = &items[i];
356                                 
357                                 item->socket_index = i;
358                                 item->socket_type = stemp->type;
359                                 item->socket_name = stemp->name;
360                                 item->node_name = arg->node_type->ui_name;
361                         }
362                 }
363         }
364         
365         *r_items = items;
366         *r_totitems = totitems;
367 }
368
369 static void ui_node_link(bContext *C, void *arg_p, void *event_p)
370 {
371         NodeLinkArg *arg = (NodeLinkArg *)arg_p;
372         Main *bmain = arg->bmain;
373         bNode *node_to = arg->node;
374         bNodeSocket *sock_to = arg->sock;
375         bNodeTree *ntree = arg->ntree;
376         int event = GET_INT_FROM_POINTER(event_p);
377
378         if (event == UI_NODE_LINK_DISCONNECT)
379                 node_socket_disconnect(bmain, ntree, node_to, sock_to);
380         else if (event == UI_NODE_LINK_REMOVE)
381                 node_socket_remove(bmain, ntree, node_to, sock_to);
382         else
383                 node_socket_add_replace(C, ntree, node_to, sock_to, arg->node_type->type, &arg->item);
384
385         ED_undo_push(C, "Node input modify");
386 }
387
388 static void ui_node_sock_name(bNodeSocket *sock, char name[UI_MAX_NAME_STR])
389 {
390         if (sock->link && sock->link->fromnode) {
391                 bNode *node = sock->link->fromnode;
392                 char node_name[UI_MAX_NAME_STR];
393
394                 if (node->type == NODE_GROUP) {
395                         if (node->id)
396                                 BLI_strncpy(node_name, node->id->name + 2, UI_MAX_NAME_STR);
397                         else
398                                 BLI_strncpy(node_name, N_(node->typeinfo->ui_name), UI_MAX_NAME_STR);
399                 }
400                 else
401                         BLI_strncpy(node_name, node->typeinfo->ui_name, UI_MAX_NAME_STR);
402
403                 if (BLI_listbase_is_empty(&node->inputs) &&
404                     node->outputs.first != node->outputs.last)
405                 {
406                         BLI_snprintf(name, UI_MAX_NAME_STR, "%s | %s", IFACE_(node_name), IFACE_(sock->link->fromsock->name));
407                 }
408                 else {
409                         BLI_strncpy(name, IFACE_(node_name), UI_MAX_NAME_STR);
410                 }
411         }
412         else if (sock->type == SOCK_SHADER)
413                 BLI_strncpy(name, IFACE_("None"), UI_MAX_NAME_STR);
414         else
415                 BLI_strncpy(name, IFACE_("Default"), UI_MAX_NAME_STR);
416 }
417
418 static int ui_compatible_sockets(int typeA, int typeB)
419 {
420         return (typeA == typeB);
421 }
422
423 static void ui_node_menu_column(NodeLinkArg *arg, int nclass, const char *cname)
424 {
425         bNodeTree *ntree = arg->ntree;
426         bNodeSocket *sock = arg->sock;
427         uiLayout *layout = arg->layout;
428         uiLayout *column = NULL;
429         uiBlock *block = uiLayoutGetBlock(layout);
430         uiBut *but;
431         NodeLinkArg *argN;
432         int first = 1;
433         int compatibility = 0;
434         
435         if (ntree->type == NTREE_SHADER) {
436                 if (BKE_scene_use_new_shading_nodes(arg->scene))
437                         compatibility = NODE_NEW_SHADING;
438                 else
439                         compatibility = NODE_OLD_SHADING;
440         }
441
442         NODE_TYPES_BEGIN(ntype) {
443                 NodeLinkItem *items;
444                 int totitems;
445                 char name[UI_MAX_NAME_STR];
446                 const char *cur_node_name = NULL;
447                 int i, num = 0;
448                 int icon = ICON_NONE;
449                 
450                 if (compatibility && !(ntype->compatibility & compatibility))
451                         continue;
452                 
453                 if (ntype->nclass != nclass)
454                         continue;
455                 
456                 arg->node_type = ntype;
457                 
458                 ui_node_link_items(arg, SOCK_OUT, &items, &totitems);
459                 
460                 for (i = 0; i < totitems; ++i)
461                         if (ui_compatible_sockets(items[i].socket_type, sock->type))
462                                 num++;
463                 
464                 for (i = 0; i < totitems; ++i) {
465                         if (!ui_compatible_sockets(items[i].socket_type, sock->type))
466                                 continue;
467                         
468                         if (first) {
469                                 column = uiLayoutColumn(layout, 0);
470                                 UI_block_layout_set_current(block, column);
471                                 
472                                 uiItemL(column, IFACE_(cname), ICON_NODE);
473                                 but = block->buttons.last;
474                                 
475                                 first = 0;
476                         }
477                         
478                         if (num > 1) {
479                                 if (!cur_node_name || !STREQ(cur_node_name, items[i].node_name)) {
480                                         cur_node_name = items[i].node_name;
481                                         /* XXX Do not use uiItemL here, it would add an empty icon as we are in a menu! */
482                                         uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_(cur_node_name), 0, 0, UI_UNIT_X * 4, UI_UNIT_Y,
483                                                  NULL, 0.0, 0.0, 0.0, 0.0, "");
484                                 }
485
486                                 BLI_snprintf(name, UI_MAX_NAME_STR, "%s", IFACE_(items[i].socket_name));
487                                 icon = ICON_BLANK1;
488                         }
489                         else {
490                                 BLI_strncpy(name, IFACE_(items[i].node_name), UI_MAX_NAME_STR);
491                                 icon = ICON_NONE;
492                         }
493                         
494                         but = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, icon, name, 0, 0, UI_UNIT_X * 4, UI_UNIT_Y,
495                                                NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Add node to input"));
496                         
497                         argN = MEM_dupallocN(arg);
498                         argN->item = items[i];
499                         UI_but_funcN_set(but, ui_node_link, argN, NULL);
500                 }
501                 
502                 if (items)
503                         MEM_freeN(items);
504         }
505         NODE_TYPES_END
506 }
507
508 static void node_menu_column_foreach_cb(void *calldata, int nclass, const char *name)
509 {
510         NodeLinkArg *arg = (NodeLinkArg *)calldata;
511
512         if (!ELEM(nclass, NODE_CLASS_GROUP, NODE_CLASS_LAYOUT))
513                 ui_node_menu_column(arg, nclass, name);
514 }
515
516 static void ui_template_node_link_menu(bContext *C, uiLayout *layout, void *but_p)
517 {
518         Main *bmain = CTX_data_main(C);
519         Scene *scene = CTX_data_scene(C);
520         uiBlock *block = uiLayoutGetBlock(layout);
521         uiBut *but = (uiBut *)but_p;
522         uiLayout *split, *column;
523         NodeLinkArg *arg = (NodeLinkArg *)but->func_argN;
524         bNodeSocket *sock = arg->sock;
525         bNodeTreeType *ntreetype = arg->ntree->typeinfo;
526
527         UI_block_flag_enable(block, UI_BLOCK_NO_FLIP);
528         UI_block_layout_set_current(block, layout);
529         split = uiLayoutSplit(layout, 0.0f, false);
530
531         arg->bmain = bmain;
532         arg->scene = scene;
533         arg->layout = split;
534
535         if (ntreetype && ntreetype->foreach_nodeclass)
536                 ntreetype->foreach_nodeclass(scene, arg, node_menu_column_foreach_cb);
537
538         column = uiLayoutColumn(split, false);
539         UI_block_layout_set_current(block, column);
540
541         if (sock->link) {
542                 uiItemL(column, IFACE_("Link"), ICON_NONE);
543                 but = block->buttons.last;
544                 but->drawflag = UI_BUT_TEXT_LEFT;
545
546                 but = uiDefBut(block, UI_BTYPE_BUT, 0, IFACE_("Remove"), 0, 0, UI_UNIT_X * 4, UI_UNIT_Y,
547                                NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Remove nodes connected to the input"));
548                 UI_but_funcN_set(but, ui_node_link, MEM_dupallocN(arg), SET_INT_IN_POINTER(UI_NODE_LINK_REMOVE));
549
550                 but = uiDefBut(block, UI_BTYPE_BUT, 0, IFACE_("Disconnect"), 0, 0, UI_UNIT_X * 4, UI_UNIT_Y,
551                                NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Disconnect nodes connected to the input"));
552                 UI_but_funcN_set(but, ui_node_link, MEM_dupallocN(arg), SET_INT_IN_POINTER(UI_NODE_LINK_DISCONNECT));
553         }
554
555         ui_node_menu_column(arg, NODE_CLASS_GROUP, N_("Group"));
556 }
557
558 void uiTemplateNodeLink(uiLayout *layout, bNodeTree *ntree, bNode *node, bNodeSocket *sock)
559 {
560         uiBlock *block = uiLayoutGetBlock(layout);
561         NodeLinkArg *arg;
562         uiBut *but;
563
564         arg = MEM_callocN(sizeof(NodeLinkArg), "NodeLinkArg");
565         arg->ntree = ntree;
566         arg->node = node;
567         arg->sock = sock;
568
569         UI_block_layout_set_current(block, layout);
570
571         if (sock->link || sock->type == SOCK_SHADER || (sock->flag & SOCK_HIDE_VALUE)) {
572                 char name[UI_MAX_NAME_STR];
573                 ui_node_sock_name(sock, name);
574                 but = uiDefMenuBut(block, ui_template_node_link_menu, NULL, name, 0, 0, UI_UNIT_X * 4, UI_UNIT_Y, "");
575         }
576         else
577                 but = uiDefIconMenuBut(block, ui_template_node_link_menu, NULL, ICON_NONE, 0, 0, UI_UNIT_X, UI_UNIT_Y, "");
578
579         UI_but_type_set_menu_from_pulldown(but);
580
581         but->flag |= UI_BUT_NODE_LINK;
582         but->poin = (char *)but;
583         but->func_argN = arg;
584
585         if (sock->link && sock->link->fromnode)
586                 if (sock->link->fromnode->flag & NODE_ACTIVE_TEXTURE)
587                         but->flag |= UI_BUT_NODE_ACTIVE;
588 }
589
590 /**************************** Node Tree Layout *******************************/
591
592 static void ui_node_draw_input(uiLayout *layout, bContext *C,
593                                bNodeTree *ntree, bNode *node, bNodeSocket *input, int depth);
594
595 static void ui_node_draw_node(uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, int depth)
596 {
597         bNodeSocket *input;
598         uiLayout *col, *split;
599         PointerRNA nodeptr;
600
601         RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr);
602
603         if (node->typeinfo->draw_buttons) {
604                 if (node->type != NODE_GROUP) {
605                         split = uiLayoutSplit(layout, 0.35f, false);
606                         col = uiLayoutColumn(split, false);
607                         col = uiLayoutColumn(split, false);
608
609                         node->typeinfo->draw_buttons(col, C, &nodeptr);
610                 }
611         }
612
613         for (input = node->inputs.first; input; input = input->next)
614                 ui_node_draw_input(layout, C, ntree, node, input, depth + 1);
615 }
616
617 static void ui_node_draw_input(uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *input, int depth)
618 {
619         PointerRNA inputptr, nodeptr;
620         uiBlock *block = uiLayoutGetBlock(layout);
621         uiBut *bt;
622         uiLayout *split, *row, *col;
623         bNode *lnode;
624         char label[UI_MAX_NAME_STR];
625         int i, indent = (depth > 1) ? 2 * (depth - 1) : 0;
626         int dependency_loop;
627
628         if (input->flag & SOCK_UNAVAIL)
629                 return;
630
631         /* to avoid eternal loops on cyclic dependencies */
632         node->flag |= NODE_TEST;
633         lnode = (input->link) ? input->link->fromnode : NULL;
634
635         dependency_loop = (lnode && (lnode->flag & NODE_TEST));
636         if (dependency_loop)
637                 lnode = NULL;
638
639         /* socket RNA pointer */
640         RNA_pointer_create(&ntree->id, &RNA_NodeSocket, input, &inputptr);
641         RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr);
642
643         /* indented label */
644         for (i = 0; i < indent; i++)
645                 label[i] = ' ';
646         label[indent] = '\0';
647         BLI_snprintf(label, UI_MAX_NAME_STR, "%s%s:", label, IFACE_(input->name));
648
649         /* split in label and value */
650         split = uiLayoutSplit(layout, 0.35f, false);
651
652         row = uiLayoutRow(split, true);
653
654         if (depth > 0) {
655                 UI_block_emboss_set(block, UI_EMBOSS_NONE);
656
657                 if (lnode && (lnode->inputs.first || (lnode->typeinfo->draw_buttons && lnode->type != NODE_GROUP))) {
658                         int icon = (input->flag & SOCK_COLLAPSED) ? ICON_DISCLOSURE_TRI_RIGHT : ICON_DISCLOSURE_TRI_DOWN;
659                         uiItemR(row, &inputptr, "show_expanded", UI_ITEM_R_ICON_ONLY, "", icon);
660                 }
661                 else
662                         uiItemL(row, "", ICON_BLANK1);
663
664                 bt = block->buttons.last;
665                 bt->rect.xmax = UI_UNIT_X / 2;
666
667                 UI_block_emboss_set(block, UI_EMBOSS);
668         }
669
670         uiItemL(row, label, ICON_NONE);
671         bt = block->buttons.last;
672         bt->drawflag = UI_BUT_TEXT_LEFT;
673
674         if (dependency_loop) {
675                 row = uiLayoutRow(split, false);
676                 uiItemL(row, IFACE_("Dependency Loop"), ICON_ERROR);
677         }
678         else if (lnode) {
679                 /* input linked to a node */
680                 uiTemplateNodeLink(split, ntree, node, input);
681
682                 if (depth == 0 || !(input->flag & SOCK_COLLAPSED)) {
683                         if (depth == 0)
684                                 uiItemS(layout);
685
686                         ui_node_draw_node(layout, C, ntree, lnode, depth);
687                 }
688         }
689         else {
690                 /* input not linked, show value */
691                 if (!(input->flag & SOCK_HIDE_VALUE)) {
692                         switch (input->type) {
693                                 case SOCK_FLOAT:
694                                 case SOCK_INT:
695                                 case SOCK_BOOLEAN:
696                                 case SOCK_RGBA:
697                                 case SOCK_STRING:
698                                         row = uiLayoutRow(split, true);
699                                         uiItemR(row, &inputptr, "default_value", 0, "", ICON_NONE);
700                                         break;
701                                 case SOCK_VECTOR:
702                                         row = uiLayoutRow(split, false);
703                                         col = uiLayoutColumn(row, false);
704                                         uiItemR(col, &inputptr, "default_value", 0, "", ICON_NONE);
705                                         break;
706                                         
707                                 default:
708                                         row = uiLayoutRow(split, false);
709                                         break;
710                         }
711                 }
712                 else
713                         row = uiLayoutRow(split, false);
714
715                 uiTemplateNodeLink(row, ntree, node, input);
716         }
717
718         /* clear */
719         node->flag &= ~NODE_TEST;
720 }
721
722 void uiTemplateNodeView(uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *input)
723 {
724         bNode *tnode;
725
726         if (!ntree)
727                 return;
728
729         /* clear for cycle check */
730         for (tnode = ntree->nodes.first; tnode; tnode = tnode->next)
731                 tnode->flag &= ~NODE_TEST;
732
733         if (input)
734                 ui_node_draw_input(layout, C, ntree, node, input, 0);
735         else
736                 ui_node_draw_node(layout, C, ntree, node, 0);
737 }
738