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