Merge branch 'master' into blender2.8
[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_array.h"
36 #include "BLI_listbase.h"
37 #include "BLI_string.h"
38
39 #include "BLT_translation.h"
40
41 #include "BKE_context.h"
42 #include "BKE_global.h"
43 #include "BKE_library.h"
44 #include "BKE_main.h"
45 #include "BKE_scene.h"
46
47 #include "RNA_access.h"
48
49 #include "NOD_socket.h"
50
51 #include "UI_interface.h"
52 #include "../interface/interface_intern.h"  /* XXX bad level */
53
54 #include "ED_node.h"  /* own include */
55
56 #include "ED_undo.h"
57
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(Main *bmain, bNode *node, NodeLinkItem *item)
86 {
87         if (node->type == NODE_GROUP) {
88                 node->id = (ID *)item->ngroup;
89                 ntreeUpdateTree(bmain, 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                                 id_us_min(node->id);
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, node_to);
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, node_to);
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         Main *bmain = CTX_data_main(C);
195         bNode *node_from;
196         bNodeSocket *sock_from_tmp;
197         bNode *node_prev = NULL;
198
199         /* unlink existing node */
200         if (sock_to->link) {
201                 node_prev = sock_to->link->fromnode;
202                 nodeRemLink(ntree, sock_to->link);
203         }
204
205         /* find existing node that we can use */
206         for (node_from = ntree->nodes.first; node_from; node_from = node_from->next)
207                 if (node_from->type == type)
208                         break;
209
210         if (node_from)
211                 if (node_from->inputs.first || node_from->typeinfo->draw_buttons || node_from->typeinfo->draw_buttons_ex)
212                         node_from = NULL;
213
214         if (node_prev && node_prev->type == type && node_link_item_compare(node_prev, item)) {
215                 /* keep the previous node if it's the same type */
216                 node_from = node_prev;
217         }
218         else if (!node_from) {
219                 node_from = nodeAddStaticNode(C, ntree, type);
220                 if (node_prev != NULL) {
221                         /* If we're replacing existing node, use it's location. */
222                         node_from->locx = node_prev->locx;
223                         node_from->locy = node_prev->locy;
224                         node_from->offsetx = node_prev->offsetx;
225                         node_from->offsety = node_prev->offsety;
226                 }
227                 else {
228                         /* Avoid exact intersection of nodes.
229                          * TODO(sergey): Still not ideal, but better than nothing.
230                          */
231                         int index = BLI_findindex(&node_to->inputs, sock_to);
232                         BLI_assert(index != -1);
233                         node_from->locx = node_to->locx - (node_from->typeinfo->width + 50);
234                         node_from->locy = node_to->locy - (node_from->typeinfo->height * index);
235                 }
236
237                 node_link_item_apply(bmain, node_from, item);
238         }
239
240         nodeSetActive(ntree, node_from);
241
242         /* add link */
243         sock_from_tmp = BLI_findlink(&node_from->outputs, item->socket_index);
244         nodeAddLink(ntree, node_from, sock_from_tmp, node_to, sock_to);
245         sock_to->flag &= ~SOCK_COLLAPSED;
246
247         /* copy input sockets from previous node */
248         if (node_prev && node_from != node_prev) {
249                 bNodeSocket *sock_prev, *sock_from;
250
251                 for (sock_prev = node_prev->inputs.first; sock_prev; sock_prev = sock_prev->next) {
252                         for (sock_from = node_from->inputs.first; sock_from; sock_from = sock_from->next) {
253                                 if (nodeCountSocketLinks(ntree, sock_from) >= sock_from->limit)
254                                         continue;
255
256                                 if (STREQ(sock_prev->name, sock_from->name) && sock_prev->type == sock_from->type) {
257                                         bNodeLink *link = sock_prev->link;
258
259                                         if (link && link->fromnode) {
260                                                 nodeAddLink(ntree, link->fromnode, link->fromsock, node_from, sock_from);
261                                                 nodeRemLink(ntree, link);
262                                         }
263
264                                         node_socket_copy_default_value(sock_from, sock_prev);
265                                 }
266                         }
267                 }
268
269                 /* also preserve mapping for texture nodes */
270                 if (node_from->typeinfo->nclass == NODE_CLASS_TEXTURE &&
271                     node_prev->typeinfo->nclass == NODE_CLASS_TEXTURE)
272                 {
273                         memcpy(node_from->storage, node_prev->storage, sizeof(NodeTexBase));
274                 }
275
276                 /* remove node */
277                 node_remove_linked(ntree, node_prev);
278         }
279
280         nodeUpdate(ntree, node_from);
281         nodeUpdate(ntree, node_to);
282         ntreeUpdateTree(CTX_data_main(C), ntree);
283
284         ED_node_tag_update_nodetree(CTX_data_main(C), ntree, node_to);
285 }
286
287 /****************************** Node Link Menu *******************************/
288
289 // #define UI_NODE_LINK_ADD        0
290 #define UI_NODE_LINK_DISCONNECT -1
291 #define UI_NODE_LINK_REMOVE     -2
292
293 typedef struct NodeLinkArg {
294         Main *bmain;
295         Scene *scene;
296         bNodeTree *ntree;
297         bNode *node;
298         bNodeSocket *sock;
299
300         bNodeType *node_type;
301         NodeLinkItem item;
302
303         uiLayout *layout;
304 } NodeLinkArg;
305
306 static void ui_node_link_items(NodeLinkArg *arg, int in_out, NodeLinkItem **r_items, int *r_totitems)
307 {
308         /* XXX this should become a callback for node types! */
309         NodeLinkItem *items = NULL;
310         int totitems = 0;
311
312         if (arg->node_type->type == NODE_GROUP) {
313                 bNodeTree *ngroup;
314                 int i;
315
316                 for (ngroup = arg->bmain->nodetree.first; ngroup; ngroup = ngroup->id.next) {
317                         ListBase *lb = ((in_out == SOCK_IN) ? &ngroup->inputs : &ngroup->outputs);
318                         totitems += BLI_listbase_count(lb);
319                 }
320
321                 if (totitems > 0) {
322                         items = MEM_callocN(sizeof(NodeLinkItem) * totitems, "ui node link items");
323
324                         i = 0;
325                         for (ngroup = arg->bmain->nodetree.first; ngroup; ngroup = ngroup->id.next) {
326                                 ListBase *lb = (in_out == SOCK_IN ? &ngroup->inputs : &ngroup->outputs);
327                                 bNodeSocket *stemp;
328                                 int index;
329                                 for (stemp = lb->first, index = 0; stemp; stemp = stemp->next, ++index, ++i) {
330                                         NodeLinkItem *item = &items[i];
331
332                                         item->socket_index = index;
333                                         /* note: int stemp->type is not fully reliable, not used for node group
334                                          * interface sockets. use the typeinfo->type instead.
335                                          */
336                                         item->socket_type = stemp->typeinfo->type;
337                                         item->socket_name = stemp->name;
338                                         item->node_name = ngroup->id.name + 2;
339                                         item->ngroup = ngroup;
340                                 }
341                         }
342                 }
343         }
344         else {
345                 bNodeSocketTemplate *socket_templates = (in_out == SOCK_IN ? arg->node_type->inputs : arg->node_type->outputs);
346                 bNodeSocketTemplate *stemp;
347                 int i;
348
349                 for (stemp = socket_templates; stemp && stemp->type != -1; ++stemp)
350                         ++totitems;
351
352                 if (totitems > 0) {
353                         items = MEM_callocN(sizeof(NodeLinkItem) * totitems, "ui node link items");
354
355                         i = 0;
356                         for (stemp = socket_templates; stemp && stemp->type != -1; ++stemp, ++i) {
357                                 NodeLinkItem *item = &items[i];
358
359                                 item->socket_index = i;
360                                 item->socket_type = stemp->type;
361                                 item->socket_name = stemp->name;
362                                 item->node_name = arg->node_type->ui_name;
363                         }
364                 }
365         }
366
367         *r_items = items;
368         *r_totitems = totitems;
369 }
370
371 static void ui_node_link(bContext *C, void *arg_p, void *event_p)
372 {
373         NodeLinkArg *arg = (NodeLinkArg *)arg_p;
374         Main *bmain = arg->bmain;
375         bNode *node_to = arg->node;
376         bNodeSocket *sock_to = arg->sock;
377         bNodeTree *ntree = arg->ntree;
378         int event = GET_INT_FROM_POINTER(event_p);
379
380         if (event == UI_NODE_LINK_DISCONNECT)
381                 node_socket_disconnect(bmain, ntree, node_to, sock_to);
382         else if (event == UI_NODE_LINK_REMOVE)
383                 node_socket_remove(bmain, ntree, node_to, sock_to);
384         else
385                 node_socket_add_replace(C, ntree, node_to, sock_to, arg->node_type->type, &arg->item);
386
387         ED_undo_push(C, "Node input modify");
388 }
389
390 static void ui_node_sock_name(bNodeTree *ntree, bNodeSocket *sock, char name[UI_MAX_NAME_STR])
391 {
392         if (sock->link && sock->link->fromnode) {
393                 bNode *node = sock->link->fromnode;
394                 char node_name[UI_MAX_NAME_STR];
395
396                 nodeLabel(ntree, node, node_name, sizeof(node_name));
397
398                 if (BLI_listbase_is_empty(&node->inputs) &&
399                     node->outputs.first != node->outputs.last)
400                 {
401                         BLI_snprintf(name, UI_MAX_NAME_STR, "%s | %s", IFACE_(node_name), IFACE_(sock->link->fromsock->name));
402                 }
403                 else {
404                         BLI_strncpy(name, IFACE_(node_name), UI_MAX_NAME_STR);
405                 }
406         }
407         else if (sock->type == SOCK_SHADER)
408                 BLI_strncpy(name, IFACE_("None"), UI_MAX_NAME_STR);
409         else
410                 BLI_strncpy(name, IFACE_("Default"), UI_MAX_NAME_STR);
411 }
412
413 static int ui_compatible_sockets(int typeA, int typeB)
414 {
415         return (typeA == typeB);
416 }
417
418 static int ui_node_item_name_compare(const void *a, const void *b)
419 {
420         const bNodeType *type_a = *(const bNodeType **)a;
421         const bNodeType *type_b = *(const bNodeType **)b;
422         return BLI_natstrcmp(type_a->ui_name, type_b->ui_name);
423 }
424
425 static bool ui_node_item_special_poll(const bNodeTree *UNUSED(ntree),
426                                       const bNodeType *ntype)
427 {
428         if (STREQ(ntype->idname, "ShaderNodeUVAlongStroke")) {
429                 /* TODO(sergey): Currently we don't have Freestyle nodes edited from
430                  * the buttons context, so can ignore it's nodes completely.
431                  *
432                  * However, we might want to do some extra checks here later.
433                  */
434                 return false;
435         }
436         return true;
437 }
438
439 static void ui_node_menu_column(NodeLinkArg *arg, int nclass, const char *cname)
440 {
441         bNodeTree *ntree = arg->ntree;
442         bNodeSocket *sock = arg->sock;
443         uiLayout *layout = arg->layout;
444         uiLayout *column = NULL;
445         uiBlock *block = uiLayoutGetBlock(layout);
446         uiBut *but;
447         NodeLinkArg *argN;
448         int first = 1;
449         int compatibility = 0;
450
451         if (ntree->type == NTREE_SHADER) {
452                 compatibility = NODE_NEW_SHADING;
453         }
454
455         /* generate array of node types sorted by UI name */
456         bNodeType **sorted_ntypes = NULL;
457         BLI_array_declare(sorted_ntypes);
458
459         NODE_TYPES_BEGIN(ntype) {
460                 if (compatibility && !(ntype->compatibility & compatibility)) {
461                         continue;
462                 }
463
464                 if (ntype->nclass != nclass) {
465                         continue;
466                 }
467
468                 if (!ui_node_item_special_poll(ntree, ntype)) {
469                         continue;
470                 }
471
472                 BLI_array_append(sorted_ntypes, ntype);
473         }
474         NODE_TYPES_END
475
476         qsort(sorted_ntypes, BLI_array_len(sorted_ntypes), sizeof(bNodeType *), ui_node_item_name_compare);
477
478         /* generate UI */
479         for (int j = 0; j < BLI_array_len(sorted_ntypes); j++) {
480                 bNodeType *ntype = sorted_ntypes[j];
481                 NodeLinkItem *items;
482                 int totitems;
483                 char name[UI_MAX_NAME_STR];
484                 const char *cur_node_name = NULL;
485                 int i, num = 0;
486                 int icon = ICON_NONE;
487
488                 arg->node_type = ntype;
489
490                 ui_node_link_items(arg, SOCK_OUT, &items, &totitems);
491
492                 for (i = 0; i < totitems; ++i)
493                         if (ui_compatible_sockets(items[i].socket_type, sock->type))
494                                 num++;
495
496                 for (i = 0; i < totitems; ++i) {
497                         if (!ui_compatible_sockets(items[i].socket_type, sock->type))
498                                 continue;
499
500                         if (first) {
501                                 column = uiLayoutColumn(layout, 0);
502                                 UI_block_layout_set_current(block, column);
503
504                                 uiItemL(column, IFACE_(cname), ICON_NODE);
505                                 but = block->buttons.last;
506
507                                 first = 0;
508                         }
509
510                         if (num > 1) {
511                                 if (!cur_node_name || !STREQ(cur_node_name, items[i].node_name)) {
512                                         cur_node_name = items[i].node_name;
513                                         /* XXX Do not use uiItemL here, it would add an empty icon as we are in a menu! */
514                                         uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_(cur_node_name), 0, 0, UI_UNIT_X * 4, UI_UNIT_Y,
515                                                  NULL, 0.0, 0.0, 0.0, 0.0, "");
516                                 }
517
518                                 BLI_snprintf(name, UI_MAX_NAME_STR, "%s", IFACE_(items[i].socket_name));
519                                 icon = ICON_BLANK1;
520                         }
521                         else {
522                                 BLI_strncpy(name, IFACE_(items[i].node_name), UI_MAX_NAME_STR);
523                                 icon = ICON_NONE;
524                         }
525
526                         but = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, icon, name, 0, 0, UI_UNIT_X * 4, UI_UNIT_Y,
527                                                NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Add node to input"));
528
529                         argN = MEM_dupallocN(arg);
530                         argN->item = items[i];
531                         UI_but_funcN_set(but, ui_node_link, argN, NULL);
532                 }
533
534                 if (items)
535                         MEM_freeN(items);
536         }
537
538         BLI_array_free(sorted_ntypes);
539 }
540
541 static void node_menu_column_foreach_cb(void *calldata, int nclass, const char *name)
542 {
543         NodeLinkArg *arg = (NodeLinkArg *)calldata;
544
545         if (!ELEM(nclass, NODE_CLASS_GROUP, NODE_CLASS_LAYOUT))
546                 ui_node_menu_column(arg, nclass, name);
547 }
548
549 static void ui_template_node_link_menu(bContext *C, uiLayout *layout, void *but_p)
550 {
551         Main *bmain = CTX_data_main(C);
552         Scene *scene = CTX_data_scene(C);
553         uiBlock *block = uiLayoutGetBlock(layout);
554         uiBut *but = (uiBut *)but_p;
555         uiLayout *split, *column;
556         NodeLinkArg *arg = (NodeLinkArg *)but->func_argN;
557         bNodeSocket *sock = arg->sock;
558         bNodeTreeType *ntreetype = arg->ntree->typeinfo;
559
560         UI_block_flag_enable(block, UI_BLOCK_NO_FLIP | UI_BLOCK_IS_FLIP);
561         UI_block_layout_set_current(block, layout);
562         split = uiLayoutSplit(layout, 0.0f, false);
563
564         arg->bmain = bmain;
565         arg->scene = scene;
566         arg->layout = split;
567
568         if (ntreetype && ntreetype->foreach_nodeclass)
569                 ntreetype->foreach_nodeclass(scene, arg, node_menu_column_foreach_cb);
570
571         column = uiLayoutColumn(split, false);
572         UI_block_layout_set_current(block, column);
573
574         if (sock->link) {
575                 uiItemL(column, IFACE_("Link"), ICON_NONE);
576                 but = block->buttons.last;
577                 but->drawflag = UI_BUT_TEXT_LEFT;
578
579                 but = uiDefBut(block, UI_BTYPE_BUT, 0, IFACE_("Remove"), 0, 0, UI_UNIT_X * 4, UI_UNIT_Y,
580                                NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Remove nodes connected to the input"));
581                 UI_but_funcN_set(but, ui_node_link, MEM_dupallocN(arg), SET_INT_IN_POINTER(UI_NODE_LINK_REMOVE));
582
583                 but = uiDefBut(block, UI_BTYPE_BUT, 0, IFACE_("Disconnect"), 0, 0, UI_UNIT_X * 4, UI_UNIT_Y,
584                                NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Disconnect nodes connected to the input"));
585                 UI_but_funcN_set(but, ui_node_link, MEM_dupallocN(arg), SET_INT_IN_POINTER(UI_NODE_LINK_DISCONNECT));
586         }
587
588         ui_node_menu_column(arg, NODE_CLASS_GROUP, N_("Group"));
589 }
590
591 void uiTemplateNodeLink(uiLayout *layout, bNodeTree *ntree, bNode *node, bNodeSocket *sock)
592 {
593         uiBlock *block = uiLayoutGetBlock(layout);
594         NodeLinkArg *arg;
595         uiBut *but;
596
597         arg = MEM_callocN(sizeof(NodeLinkArg), "NodeLinkArg");
598         arg->ntree = ntree;
599         arg->node = node;
600         arg->sock = sock;
601
602         UI_block_layout_set_current(block, layout);
603
604         if (sock->link || sock->type == SOCK_SHADER || (sock->flag & SOCK_HIDE_VALUE)) {
605                 char name[UI_MAX_NAME_STR];
606                 ui_node_sock_name(ntree, sock, name);
607                 but = uiDefMenuBut(block, ui_template_node_link_menu, NULL, name, 0, 0, UI_UNIT_X * 4, UI_UNIT_Y, "");
608         }
609         else
610                 but = uiDefIconMenuBut(block, ui_template_node_link_menu, NULL, ICON_NONE, 0, 0, UI_UNIT_X, UI_UNIT_Y, "");
611
612         UI_but_type_set_menu_from_pulldown(but);
613
614         but->flag |= UI_BUT_NODE_LINK;
615         but->poin = (char *)but;
616         but->func_argN = arg;
617
618         if (sock->link && sock->link->fromnode)
619                 if (sock->link->fromnode->flag & NODE_ACTIVE_TEXTURE)
620                         but->flag |= UI_BUT_NODE_ACTIVE;
621 }
622
623 /**************************** Node Tree Layout *******************************/
624
625 static void ui_node_draw_input(uiLayout *layout, bContext *C,
626                                bNodeTree *ntree, bNode *node, bNodeSocket *input, int depth);
627
628 static void ui_node_draw_node(uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, int depth)
629 {
630         bNodeSocket *input;
631         uiLayout *col, *split;
632         PointerRNA nodeptr;
633
634         RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr);
635
636         if (node->typeinfo->draw_buttons) {
637                 if (node->type != NODE_GROUP) {
638                         split = uiLayoutSplit(layout, 0.5f, false);
639                         col = uiLayoutColumn(split, false);
640                         col = uiLayoutColumn(split, false);
641
642                         node->typeinfo->draw_buttons(col, C, &nodeptr);
643                 }
644         }
645
646         for (input = node->inputs.first; input; input = input->next)
647                 ui_node_draw_input(layout, C, ntree, node, input, depth + 1);
648 }
649
650 static void ui_node_draw_input(uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *input, int depth)
651 {
652         PointerRNA inputptr, nodeptr;
653         uiBlock *block = uiLayoutGetBlock(layout);
654         uiBut *bt;
655         uiLayout *split, *row, *col;
656         bNode *lnode;
657         char label[UI_MAX_NAME_STR];
658         int i, indent = (depth > 1) ? 2 * (depth - 1) : 0;
659         int dependency_loop;
660
661         if (input->flag & SOCK_UNAVAIL)
662                 return;
663
664         /* to avoid eternal loops on cyclic dependencies */
665         node->flag |= NODE_TEST;
666         lnode = (input->link) ? input->link->fromnode : NULL;
667
668         dependency_loop = (lnode && (lnode->flag & NODE_TEST));
669         if (dependency_loop)
670                 lnode = NULL;
671
672         /* socket RNA pointer */
673         RNA_pointer_create(&ntree->id, &RNA_NodeSocket, input, &inputptr);
674         RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr);
675
676         /* indented label */
677         for (i = 0; i < indent; i++) {
678                 label[i] = ' ';
679         }
680         label[indent] = '\0';
681         BLI_snprintf(label + indent, UI_MAX_NAME_STR - indent, "%s", IFACE_(input->name));
682
683         /* split in label and value */
684         split = uiLayoutSplit(layout, 0.5f, false);
685
686         row = uiLayoutRow(split, true);
687
688         if (depth > 0) {
689                 UI_block_emboss_set(block, UI_EMBOSS_NONE);
690
691                 if (lnode && (lnode->inputs.first || (lnode->typeinfo->draw_buttons && lnode->type != NODE_GROUP))) {
692                         int icon = (input->flag & SOCK_COLLAPSED) ? ICON_DISCLOSURE_TRI_RIGHT : ICON_DISCLOSURE_TRI_DOWN;
693                         uiItemR(row, &inputptr, "show_expanded", UI_ITEM_R_ICON_ONLY, "", icon);
694                 }
695                 else
696                         uiItemL(row, "", ICON_BLANK1);
697
698                 bt = block->buttons.last;
699                 bt->rect.xmax = UI_UNIT_X / 2;
700
701                 UI_block_emboss_set(block, UI_EMBOSS);
702         }
703
704         uiItemL(row, label, ICON_NONE);
705         bt = block->buttons.last;
706         bt->drawflag = UI_BUT_TEXT_RIGHT;
707
708         if (dependency_loop) {
709                 row = uiLayoutRow(split, false);
710                 uiItemL(row, IFACE_("Dependency Loop"), ICON_ERROR);
711         }
712         else if (lnode) {
713                 /* input linked to a node */
714                 uiTemplateNodeLink(split, ntree, node, input);
715
716                 if (depth == 0 || !(input->flag & SOCK_COLLAPSED)) {
717                         if (depth == 0)
718                                 uiItemS(layout);
719
720                         ui_node_draw_node(layout, C, ntree, lnode, depth);
721                 }
722         }
723         else {
724                 /* input not linked, show value */
725                 if (!(input->flag & SOCK_HIDE_VALUE)) {
726                         switch (input->type) {
727                                 case SOCK_FLOAT:
728                                 case SOCK_INT:
729                                 case SOCK_BOOLEAN:
730                                 case SOCK_RGBA:
731                                 case SOCK_STRING:
732                                         row = uiLayoutRow(split, true);
733                                         uiItemR(row, &inputptr, "default_value", 0, "", ICON_NONE);
734                                         break;
735                                 case SOCK_VECTOR:
736                                         row = uiLayoutRow(split, false);
737                                         col = uiLayoutColumn(row, false);
738                                         uiItemR(col, &inputptr, "default_value", 0, "", ICON_NONE);
739                                         break;
740
741                                 default:
742                                         row = uiLayoutRow(split, false);
743                                         break;
744                         }
745                 }
746                 else
747                         row = uiLayoutRow(split, false);
748
749                 uiTemplateNodeLink(row, ntree, node, input);
750         }
751
752         /* clear */
753         node->flag &= ~NODE_TEST;
754 }
755
756 void uiTemplateNodeView(uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *input)
757 {
758         bNode *tnode;
759
760         if (!ntree)
761                 return;
762
763         /* clear for cycle check */
764         for (tnode = ntree->nodes.first; tnode; tnode = tnode->next)
765                 tnode->flag &= ~NODE_TEST;
766
767         if (input)
768                 ui_node_draw_input(layout, C, ntree, node, input, 0);
769         else
770                 ui_node_draw_node(layout, C, ntree, node, 0);
771 }
772