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