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