code cleanup: remove unused and unsupported functions from libmv-capi
[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 <string.h>
28
29 #include "MEM_guardedalloc.h"
30
31 #include "DNA_node_types.h"
32 #include "DNA_screen_types.h"
33 #include "DNA_space_types.h"
34
35 #include "BLI_listbase.h"
36 #include "BLI_string.h"
37
38 #include "BLF_translation.h"
39
40 #include "BKE_context.h"
41 #include "BKE_library.h"
42 #include "BKE_main.h"
43 #include "BKE_scene.h"
44
45 #include "RNA_access.h"
46
47 #include "NOD_socket.h"
48
49 #include "UI_interface.h"
50 #include "../interface/interface_intern.h"  /* XXX bad level */
51
52 #include "ED_node.h"  /* own include */
53
54 #include "ED_util.h"
55
56 #include "node_intern.h"
57
58 /************************* Node Socket Manipulation **************************/
59
60 static void node_tag_recursive(bNode *node)
61 {
62         bNodeSocket *input;
63
64         if (!node || (node->flag & NODE_TEST))
65                 return;  /* in case of cycles */
66
67         node->flag |= NODE_TEST;
68
69         for (input = node->inputs.first; input; input = input->next)
70                 if (input->link)
71                         node_tag_recursive(input->link->fromnode);
72 }
73
74 static void node_clear_recursive(bNode *node)
75 {
76         bNodeSocket *input;
77
78         if (!node || !(node->flag & NODE_TEST))
79                 return;  /* in case of cycles */
80
81         node->flag &= ~NODE_TEST;
82
83         for (input = node->inputs.first; input; input = input->next)
84                 if (input->link)
85                         node_clear_recursive(input->link->fromnode);
86 }
87
88 static void node_remove_linked(bNodeTree *ntree, bNode *rem_node)
89 {
90         bNode *node, *next;
91         bNodeSocket *sock;
92
93         if (!rem_node)
94                 return;
95
96         /* tag linked nodes to be removed */
97         for (node = ntree->nodes.first; node; node = node->next)
98                 node->flag &= ~NODE_TEST;
99
100         node_tag_recursive(rem_node);
101
102         /* clear tags on nodes that are still used by other nodes */
103         for (node = ntree->nodes.first; node; node = node->next)
104                 if (!(node->flag & NODE_TEST))
105                         for (sock = node->inputs.first; sock; sock = sock->next)
106                                 if (sock->link && sock->link->fromnode != rem_node)
107                                         node_clear_recursive(sock->link->fromnode);
108
109         /* remove nodes */
110         for (node = ntree->nodes.first; node; node = next) {
111                 next = node->next;
112
113                 if (node->flag & NODE_TEST) {
114                         if (node->id)
115                                 node->id->us--;
116                         nodeFreeNode(ntree, node);
117                 }
118         }
119 }
120
121 /* disconnect socket from the node it is connected to */
122 static void node_socket_disconnect(Main *bmain, bNodeTree *ntree, bNode *node_to, bNodeSocket *sock_to)
123 {
124         if (!sock_to->link)
125                 return;
126
127         nodeRemLink(ntree, sock_to->link);
128         sock_to->flag |= SOCK_COLLAPSED;
129
130         nodeUpdate(ntree, node_to);
131         ntreeUpdateTree(ntree);
132
133         ED_node_generic_update(bmain, ntree, node_to);
134 }
135
136 /* remove all nodes connected to this socket, if they aren't connected to other nodes */
137 static void node_socket_remove(Main *bmain, bNodeTree *ntree, bNode *node_to, bNodeSocket *sock_to)
138 {
139         if (!sock_to->link)
140                 return;
141
142         node_remove_linked(ntree, sock_to->link->fromnode);
143         sock_to->flag |= SOCK_COLLAPSED;
144
145         nodeUpdate(ntree, node_to);
146         ntreeUpdateTree(ntree);
147
148         ED_node_generic_update(bmain, ntree, node_to);
149 }
150
151 /* add new node connected to this socket, or replace an existing one */
152 static void node_socket_add_replace(Main *bmain, bNodeTree *ntree, bNode *node_to, bNodeSocket *sock_to, bNodeTemplate *ntemp, int sock_num)
153 {
154         bNode *node_from;
155         bNodeSocket *sock_from_tmp;
156         bNode *node_prev = NULL;
157
158         /* unlink existing node */
159         if (sock_to->link) {
160                 node_prev = sock_to->link->fromnode;
161                 nodeRemLink(ntree, sock_to->link);
162         }
163
164         /* find existing node that we can use */
165         for (node_from = ntree->nodes.first; node_from; node_from = node_from->next)
166                 if (node_from->type == ntemp->type)
167                         break;
168
169         if (node_from)
170                 if (!(node_from->inputs.first == NULL && !(node_from->typeinfo->flag & NODE_OPTIONS)))
171                         node_from = NULL;
172
173         if (node_prev && node_prev->type == ntemp->type &&
174             (ntemp->type != NODE_GROUP || node_prev->id == &ntemp->ngroup->id))
175         {
176                 /* keep the previous node if it's the same type */
177                 node_from = node_prev;
178         }
179         else if (!node_from) {
180                 node_from = nodeAddNode(ntree, ntemp);
181                 node_from->locx = node_to->locx - (node_from->typeinfo->width + 50);
182                 node_from->locy = node_to->locy;
183
184                 if (node_from->id)
185                         id_us_plus(node_from->id);
186         }
187
188         nodeSetActive(ntree, node_from);
189
190         /* add link */
191         sock_from_tmp = BLI_findlink(&node_from->outputs, sock_num);
192         nodeAddLink(ntree, node_from, sock_from_tmp, node_to, sock_to);
193         sock_to->flag &= ~SOCK_COLLAPSED;
194
195         /* copy input sockets from previous node */
196         if (node_prev && node_from != node_prev) {
197                 bNodeSocket *sock_prev, *sock_from;
198
199                 for (sock_prev = node_prev->inputs.first; sock_prev; sock_prev = sock_prev->next) {
200                         for (sock_from = node_from->inputs.first; sock_from; sock_from = sock_from->next) {
201                                 if (nodeCountSocketLinks(ntree, sock_from) >= sock_from->limit)
202                                         continue;
203
204                                 if (strcmp(sock_prev->name, sock_from->name) == 0 && sock_prev->type == sock_from->type) {
205                                         bNodeLink *link = sock_prev->link;
206
207                                         if (link && link->fromnode) {
208                                                 nodeAddLink(ntree, link->fromnode, link->fromsock, node_from, sock_from);
209                                                 nodeRemLink(ntree, link);
210                                         }
211
212                                         node_socket_free_default_value(sock_from->type, sock_from->default_value);
213                                         sock_from->default_value = node_socket_make_default_value(sock_from->type);
214                                         node_socket_copy_default_value(sock_from->type, sock_from->default_value, sock_prev->default_value);
215                                 }
216                         }
217                 }
218
219                 /* also preserve mapping for texture nodes */
220                 if (node_from->typeinfo->nclass == NODE_CLASS_TEXTURE &&
221                     node_prev->typeinfo->nclass == NODE_CLASS_TEXTURE)
222                 {
223                         memcpy(node_from->storage, node_prev->storage, sizeof(NodeTexBase));
224                 }
225
226                 /* remove node */
227                 node_remove_linked(ntree, node_prev);
228         }
229
230         nodeUpdate(ntree, node_from);
231         nodeUpdate(ntree, node_to);
232         ntreeUpdateTree(ntree);
233
234         ED_node_generic_update(bmain, ntree, node_to);
235 }
236
237 /****************************** Node Link Menu *******************************/
238
239 // #define UI_NODE_LINK_ADD        0
240 #define UI_NODE_LINK_DISCONNECT -1
241 #define UI_NODE_LINK_REMOVE     -2
242
243 typedef struct NodeLinkArg {
244         Main *bmain;
245         Scene *scene;
246         bNodeTree *ntree;
247         bNode *node;
248         bNodeSocket *sock;
249
250         bNodeTree *ngroup;
251         int type;
252         int output;
253
254         uiLayout *layout;
255 } NodeLinkArg;
256
257 static void ui_node_link(bContext *C, void *arg_p, void *event_p)
258 {
259         NodeLinkArg *arg = (NodeLinkArg *)arg_p;
260         Main *bmain = arg->bmain;
261         bNode *node_to = arg->node;
262         bNodeSocket *sock_to = arg->sock;
263         bNodeTree *ntree = arg->ntree;
264         int event = GET_INT_FROM_POINTER(event_p);
265         bNodeTemplate ntemp;
266
267         ntemp.type = arg->type;
268         ntemp.ngroup = arg->ngroup;
269         ntemp.scene = CTX_data_scene(C);
270         ntemp.main = CTX_data_main(C);
271
272         if (event == UI_NODE_LINK_DISCONNECT)
273                 node_socket_disconnect(bmain, ntree, node_to, sock_to);
274         else if (event == UI_NODE_LINK_REMOVE)
275                 node_socket_remove(bmain, ntree, node_to, sock_to);
276         else
277                 node_socket_add_replace(bmain, ntree, node_to, sock_to, &ntemp, arg->output);
278
279         ED_undo_push(C, "Node input modify");
280 }
281
282 static void ui_node_sock_name(bNodeSocket *sock, char name[UI_MAX_NAME_STR])
283 {
284         if (sock->link && sock->link->fromnode) {
285                 bNode *node = sock->link->fromnode;
286                 char node_name[UI_MAX_NAME_STR];
287
288                 if (node->type == NODE_GROUP) {
289                         if (node->id)
290                                 BLI_strncpy(node_name, node->id->name + 2, UI_MAX_NAME_STR);
291                         else
292                                 BLI_strncpy(node_name, N_("Group"), UI_MAX_NAME_STR);
293                 }
294                 else
295                         BLI_strncpy(node_name, node->typeinfo->name, UI_MAX_NAME_STR);
296
297                 if (node->inputs.first == NULL &&
298                     node->outputs.first != node->outputs.last)
299                 {
300                         BLI_snprintf(name, UI_MAX_NAME_STR, "%s | %s", IFACE_(node_name), IFACE_(sock->link->fromsock->name));
301                 }
302                 else {
303                         BLI_strncpy(name, IFACE_(node_name), UI_MAX_NAME_STR);
304                 }
305         }
306         else if (sock->type == SOCK_SHADER)
307                 BLI_strncpy(name, IFACE_("None"), UI_MAX_NAME_STR);
308         else
309                 BLI_strncpy(name, IFACE_("Default"), UI_MAX_NAME_STR);
310 }
311
312 static int ui_compatible_sockets(int typeA, int typeB)
313 {
314         return (typeA == typeB);
315 }
316
317 static void ui_node_menu_column(NodeLinkArg *arg, int nclass, const char *cname)
318 {
319         Main *bmain = arg->bmain;
320         bNodeTree *ntree = arg->ntree;
321         bNodeSocket *sock = arg->sock;
322         uiLayout *layout = arg->layout;
323         uiLayout *column = NULL;
324         uiBlock *block = uiLayoutGetBlock(layout);
325         uiBut *but;
326         bNodeType *ntype;
327         bNodeTree *ngroup;
328         NodeLinkArg *argN;
329         int first = 1;
330         int compatibility = 0;
331
332         if (ntree->type == NTREE_SHADER) {
333                 if (BKE_scene_use_new_shading_nodes(arg->scene))
334                         compatibility = NODE_NEW_SHADING;
335                 else
336                         compatibility = NODE_OLD_SHADING;
337         }
338
339         if (nclass == NODE_CLASS_GROUP) {
340                 for (ngroup = bmain->nodetree.first; ngroup; ngroup = ngroup->id.next) {
341                         bNodeSocket *gsock;
342                         char name[UI_MAX_NAME_STR];
343                         int i, j, num = 0;
344
345                         if (ngroup->type != ntree->type)
346                                 continue;
347
348                         for (gsock = ngroup->inputs.first; gsock; gsock = gsock->next)
349                                 if (ui_compatible_sockets(gsock->type, sock->type))
350                                         num++;
351
352                         for (i = 0, j = 0, gsock = ngroup->outputs.first; gsock; gsock = gsock->next, i++) {
353                                 if (!ui_compatible_sockets(gsock->type, sock->type))
354                                         continue;
355
356                                 if (first) {
357                                         column = uiLayoutColumn(layout, FALSE);
358                                         uiBlockSetCurLayout(block, column);
359
360                                         uiItemL(column, IFACE_(cname), ICON_NODE);
361                                         but = block->buttons.last;
362                                         but->flag = UI_TEXT_LEFT;
363
364                                         first = 0;
365                                 }
366
367                                 if (num > 1) {
368                                         if (j == 0) {
369                                                 uiItemL(column, ngroup->id.name + 2, ICON_NODE);
370                                                 but = block->buttons.last;
371                                                 but->flag = UI_TEXT_LEFT;
372                                         }
373
374                                         BLI_snprintf(name, UI_MAX_NAME_STR, "  %s", gsock->name);
375                                         j++;
376                                 }
377                                 else
378                                         BLI_strncpy(name, ngroup->id.name + 2, UI_MAX_NAME_STR);
379
380                                 but = uiDefBut(block, BUT, 0, ngroup->id.name + 2, 0, 0, UI_UNIT_X * 4, UI_UNIT_Y,
381                                                NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Add node to input"));
382
383                                 argN = MEM_dupallocN(arg);
384                                 argN->type = NODE_GROUP;
385                                 argN->ngroup = ngroup;
386                                 argN->output = i;
387                                 uiButSetNFunc(but, ui_node_link, argN, NULL);
388                         }
389                 }
390         }
391         else {
392                 bNodeTreeType *ttype = ntreeGetType(ntree->type);
393
394                 for (ntype = ttype->node_types.first; ntype; ntype = ntype->next) {
395                         bNodeSocketTemplate *stemp;
396                         char name[UI_MAX_NAME_STR];
397                         int i, j, num = 0;
398
399                         if (compatibility && !(ntype->compatibility & compatibility))
400                                 continue;
401
402                         if (ntype->nclass != nclass)
403                                 continue;
404
405                         for (i = 0, stemp = ntype->outputs; stemp && stemp->type != -1; stemp++, i++)
406                                 if (ui_compatible_sockets(stemp->type, sock->type))
407                                         num++;
408
409                         for (i = 0, j = 0, stemp = ntype->outputs; stemp && stemp->type != -1; stemp++, i++) {
410                                 if (!ui_compatible_sockets(stemp->type, sock->type))
411                                         continue;
412
413                                 if (first) {
414                                         column = uiLayoutColumn(layout, FALSE);
415                                         uiBlockSetCurLayout(block, column);
416
417                                         uiItemL(column, IFACE_(cname), ICON_NODE);
418                                         but = block->buttons.last;
419                                         but->flag = UI_TEXT_LEFT;
420
421                                         first = 0;
422                                 }
423
424                                 if (num > 1) {
425                                         if (j == 0) {
426                                                 uiItemL(column, IFACE_(ntype->name), ICON_NODE);
427                                                 but = block->buttons.last;
428                                                 but->flag = UI_TEXT_LEFT;
429                                         }
430
431                                         BLI_snprintf(name, UI_MAX_NAME_STR, "  %s", IFACE_(stemp->name));
432                                         j++;
433                                 }
434                                 else
435                                         BLI_strncpy(name, IFACE_(ntype->name), UI_MAX_NAME_STR);
436
437                                 but = uiDefBut(block, BUT, 0, name, 0, 0, UI_UNIT_X * 4, UI_UNIT_Y,
438                                                NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Add node to input"));
439
440                                 argN = MEM_dupallocN(arg);
441                                 argN->type = ntype->type;
442                                 argN->output = i;
443                                 uiButSetNFunc(but, ui_node_link, argN, NULL);
444                         }
445                 }
446         }
447 }
448
449 static void node_menu_column_foreach_cb(void *calldata, int nclass, const char *name)
450 {
451         NodeLinkArg *arg = (NodeLinkArg *)calldata;
452
453         if (!ELEM(nclass, NODE_CLASS_GROUP, NODE_CLASS_LAYOUT))
454                 ui_node_menu_column(arg, nclass, name);
455 }
456
457 static void ui_template_node_link_menu(bContext *C, uiLayout *layout, void *but_p)
458 {
459         Main *bmain = CTX_data_main(C);
460         Scene *scene = CTX_data_scene(C);
461         uiBlock *block = uiLayoutGetBlock(layout);
462         uiBut *but = (uiBut *)but_p;
463         uiLayout *split, *column;
464         NodeLinkArg *arg = (NodeLinkArg *)but->func_argN;
465         bNodeSocket *sock = arg->sock;
466         bNodeTreeType *ntreetype = ntreeGetType(arg->ntree->type);
467
468         uiBlockSetCurLayout(block, layout);
469         split = uiLayoutSplit(layout, 0.0f, FALSE);
470
471         arg->bmain = bmain;
472         arg->scene = scene;
473         arg->layout = split;
474
475         if (ntreetype && ntreetype->foreach_nodeclass)
476                 ntreetype->foreach_nodeclass(scene, arg, node_menu_column_foreach_cb);
477
478         column = uiLayoutColumn(split, FALSE);
479         uiBlockSetCurLayout(block, column);
480
481         if (sock->link) {
482                 uiItemL(column, IFACE_("Link"), ICON_NONE);
483                 but = block->buttons.last;
484                 but->flag = UI_TEXT_LEFT;
485
486                 but = uiDefBut(block, BUT, 0, IFACE_("Remove"), 0, 0, UI_UNIT_X * 4, UI_UNIT_Y,
487                                NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Remove nodes connected to the input"));
488                 uiButSetNFunc(but, ui_node_link, MEM_dupallocN(arg), SET_INT_IN_POINTER(UI_NODE_LINK_REMOVE));
489
490                 but = uiDefBut(block, BUT, 0, IFACE_("Disconnect"), 0, 0, UI_UNIT_X * 4, UI_UNIT_Y,
491                                NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Disconnect nodes connected to the input"));
492                 uiButSetNFunc(but, ui_node_link, MEM_dupallocN(arg), SET_INT_IN_POINTER(UI_NODE_LINK_DISCONNECT));
493         }
494
495         ui_node_menu_column(arg, NODE_CLASS_GROUP, N_("Group"));
496 }
497
498 void uiTemplateNodeLink(uiLayout *layout, bNodeTree *ntree, bNode *node, bNodeSocket *sock)
499 {
500         uiBlock *block = uiLayoutGetBlock(layout);
501         NodeLinkArg *arg;
502         uiBut *but;
503
504         arg = MEM_callocN(sizeof(NodeLinkArg), "NodeLinkArg");
505         arg->ntree = ntree;
506         arg->node = node;
507         arg->sock = sock;
508         arg->type = 0;
509         arg->output = 0;
510
511         uiBlockSetCurLayout(block, layout);
512
513         if (sock->link || sock->type == SOCK_SHADER || (sock->flag & SOCK_HIDE_VALUE)) {
514                 char name[UI_MAX_NAME_STR];
515                 ui_node_sock_name(sock, name);
516                 but = uiDefMenuBut(block, ui_template_node_link_menu, NULL, name, 0, 0, UI_UNIT_X * 4, UI_UNIT_Y, "");
517         }
518         else
519                 but = uiDefIconMenuBut(block, ui_template_node_link_menu, NULL, ICON_NONE, 0, 0, UI_UNIT_X, UI_UNIT_Y, "");
520
521         but->type = MENU;
522         but->flag |= UI_TEXT_LEFT | UI_BUT_NODE_LINK;
523         but->poin = (char *)but;
524         but->func_argN = arg;
525
526         if (sock->link && sock->link->fromnode)
527                 if (sock->link->fromnode->flag & NODE_ACTIVE_TEXTURE)
528                         but->flag |= UI_BUT_NODE_ACTIVE;
529 }
530
531 /**************************** Node Tree Layout *******************************/
532
533 static void ui_node_draw_input(uiLayout *layout, bContext *C,
534                                bNodeTree *ntree, bNode *node, bNodeSocket *input, int depth);
535
536 static void ui_node_draw_node(uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, int depth)
537 {
538         bNodeSocket *input;
539         uiLayout *col, *split;
540         PointerRNA nodeptr;
541
542         RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr);
543
544         if (node->typeinfo->uifunc) {
545                 if (node->type != NODE_GROUP) {
546                         split = uiLayoutSplit(layout, 0.35f, FALSE);
547                         col = uiLayoutColumn(split, FALSE);
548                         col = uiLayoutColumn(split, FALSE);
549
550                         node->typeinfo->uifunc(col, C, &nodeptr);
551                 }
552         }
553
554         for (input = node->inputs.first; input; input = input->next)
555                 ui_node_draw_input(layout, C, ntree, node, input, depth + 1);
556 }
557
558 static void ui_node_draw_input(uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *input, int depth)
559 {
560         PointerRNA inputptr;
561         uiBlock *block = uiLayoutGetBlock(layout);
562         uiBut *bt;
563         uiLayout *split, *row, *col;
564         bNode *lnode;
565         char label[UI_MAX_NAME_STR];
566         int indent = (depth > 1) ? 2 * (depth - 1) : 0;
567         int dependency_loop;
568
569         if (input->flag & SOCK_UNAVAIL)
570                 return;
571
572         /* to avoid eternal loops on cyclic dependencies */
573         node->flag |= NODE_TEST;
574         lnode = (input->link) ? input->link->fromnode : NULL;
575
576         dependency_loop = (lnode && (lnode->flag & NODE_TEST));
577         if (dependency_loop)
578                 lnode = NULL;
579
580         /* socket RNA pointer */
581         RNA_pointer_create(&ntree->id, &RNA_NodeSocket, input, &inputptr);
582
583         /* indented label */
584         memset(label, ' ', indent);
585         label[indent] = '\0';
586         BLI_snprintf(label, UI_MAX_NAME_STR, "%s%s:", label, IFACE_(input->name));
587
588         /* split in label and value */
589         split = uiLayoutSplit(layout, 0.35f, FALSE);
590
591         row = uiLayoutRow(split, TRUE);
592
593         if (depth > 0) {
594                 uiBlockSetEmboss(block, UI_EMBOSSN);
595
596                 if (lnode && (lnode->inputs.first || (lnode->typeinfo->uifunc && lnode->type != NODE_GROUP))) {
597                         int icon = (input->flag & SOCK_COLLAPSED) ? ICON_DISCLOSURE_TRI_RIGHT : ICON_DISCLOSURE_TRI_DOWN;
598                         uiItemR(row, &inputptr, "show_expanded", UI_ITEM_R_ICON_ONLY, "", icon);
599                 }
600                 else
601                         uiItemL(row, "", ICON_BLANK1);
602
603                 bt = block->buttons.last;
604                 bt->rect.xmax = UI_UNIT_X / 2;
605
606                 uiBlockSetEmboss(block, UI_EMBOSS);
607         }
608
609         uiItemL(row, label, ICON_NONE);
610         bt = block->buttons.last;
611         bt->flag = UI_TEXT_LEFT;
612
613         if (dependency_loop) {
614                 row = uiLayoutRow(split, FALSE);
615                 uiItemL(row, IFACE_("Dependency Loop"), ICON_ERROR);
616         }
617         else if (lnode) {
618                 /* input linked to a node */
619                 uiTemplateNodeLink(split, ntree, node, input);
620
621                 if (depth == 0 || !(input->flag & SOCK_COLLAPSED)) {
622                         if (depth == 0)
623                                 uiItemS(layout);
624
625                         ui_node_draw_node(layout, C, ntree, lnode, depth);
626                 }
627         }
628         else {
629                 /* input not linked, show value */
630                 if (input->type != SOCK_SHADER && !(input->flag & SOCK_HIDE_VALUE)) {
631                         if (input->type == SOCK_VECTOR) {
632                                 row = uiLayoutRow(split, FALSE);
633                                 col = uiLayoutColumn(row, FALSE);
634
635                                 uiItemR(col, &inputptr, "default_value", 0, "", ICON_NONE);
636                         }
637                         else {
638                                 row = uiLayoutRow(split, TRUE);
639                                 uiItemR(row, &inputptr, "default_value", 0, "", ICON_NONE);
640                         }
641                 }
642                 else
643                         row = uiLayoutRow(split, FALSE);
644
645                 uiTemplateNodeLink(row, ntree, node, input);
646         }
647
648         /* clear */
649         node->flag &= ~NODE_TEST;
650 }
651
652 void uiTemplateNodeView(uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *input)
653 {
654         bNode *tnode;
655
656         if (!ntree)
657                 return;
658
659         /* clear for cycle check */
660         for (tnode = ntree->nodes.first; tnode; tnode = tnode->next)
661                 tnode->flag &= ~NODE_TEST;
662
663         if (input)
664                 ui_node_draw_input(layout, C, ntree, node, input, 0);
665         else
666                 ui_node_draw_node(layout, C, ntree, node, 0);
667 }
668