Blender V2.61 - r43446

node_templates.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * Contributor(s): Blender Foundation 2009.
00019  *
00020  * ***** END GPL LICENSE BLOCK *****
00021  */
00022 
00027 #include <stdlib.h>
00028 #include <stddef.h>
00029 #include <string.h>
00030 
00031 #include "MEM_guardedalloc.h"
00032 
00033 #include "DNA_node_types.h"
00034 #include "DNA_scene_types.h"
00035 #include "DNA_screen_types.h"
00036 
00037 #include "BLI_listbase.h"
00038 #include "BLI_string.h"
00039 #include "BLI_utildefines.h"
00040 
00041 #include "BLF_translation.h"
00042 
00043 #include "BKE_context.h"
00044 #include "BKE_depsgraph.h"
00045 #include "BKE_library.h"
00046 #include "BKE_main.h"
00047 #include "BKE_node.h"
00048 #include "BKE_scene.h"
00049 
00050 #include "RNA_access.h"
00051 
00052 #include "WM_api.h"
00053 #include "WM_types.h"
00054 
00055 #include "UI_interface.h"
00056 #include "UI_resources.h"
00057 #include "../interface/interface_intern.h"
00058 
00059 #include "ED_node.h"
00060 
00061 /************************* Node Socket Manipulation **************************/
00062 
00063 static void node_tag_recursive(bNode *node)
00064 {
00065     bNodeSocket *input;
00066 
00067     if(!node || (node->flag & NODE_TEST))
00068         return; /* in case of cycles */
00069     
00070     node->flag |= NODE_TEST;
00071 
00072     for(input=node->inputs.first; input; input=input->next)
00073         if(input->link)
00074             node_tag_recursive(input->link->fromnode);
00075 }
00076 
00077 static void node_clear_recursive(bNode *node)
00078 {
00079     bNodeSocket *input;
00080 
00081     if(!node || !(node->flag & NODE_TEST))
00082         return; /* in case of cycles */
00083     
00084     node->flag &= ~NODE_TEST;
00085 
00086     for(input=node->inputs.first; input; input=input->next)
00087         if(input->link)
00088             node_clear_recursive(input->link->fromnode);
00089 }
00090 
00091 static void node_remove_linked(bNodeTree *ntree, bNode *rem_node)
00092 {
00093     bNode *node, *next;
00094     bNodeSocket *sock;
00095 
00096     if(!rem_node)
00097         return;
00098 
00099     /* tag linked nodes to be removed */
00100     for(node=ntree->nodes.first; node; node=node->next)
00101         node->flag &= ~NODE_TEST;
00102     
00103     node_tag_recursive(rem_node);
00104 
00105     /* clear tags on nodes that are still used by other nodes */
00106     for(node=ntree->nodes.first; node; node=node->next)
00107         if(!(node->flag & NODE_TEST))
00108             for(sock=node->inputs.first; sock; sock=sock->next)
00109                 if(sock->link && sock->link->fromnode != rem_node)
00110                     node_clear_recursive(sock->link->fromnode);
00111 
00112     /* remove nodes */
00113     for(node=ntree->nodes.first; node; node=next) {
00114         next = node->next;
00115 
00116         if(node->flag & NODE_TEST) {
00117             if(node->id)
00118                 node->id->us--;
00119             nodeFreeNode(ntree, node);
00120         }
00121     }
00122 }
00123 
00124 /* disconnect socket from the node it is connected to */
00125 static void node_socket_disconnect(Main *bmain, bNodeTree *ntree, bNode *node_to, bNodeSocket *sock_to)
00126 {
00127     if(!sock_to->link)
00128         return;
00129 
00130     nodeRemLink(ntree, sock_to->link);
00131 
00132     nodeUpdate(ntree, node_to);
00133     ntreeUpdateTree(ntree);
00134 
00135     ED_node_generic_update(bmain, ntree, node_to);
00136 }
00137 
00138 /* remove all nodes connected to this socket, if they aren't connected to other nodes */
00139 static void node_socket_remove(Main *bmain, bNodeTree *ntree, bNode *node_to, bNodeSocket *sock_to)
00140 {
00141     if(!sock_to->link)
00142         return;
00143 
00144     node_remove_linked(ntree, sock_to->link->fromnode);
00145 
00146     nodeUpdate(ntree, node_to);
00147     ntreeUpdateTree(ntree);
00148 
00149     ED_node_generic_update(bmain, ntree, node_to);
00150 }
00151 
00152 /* add new node connected to this socket, or replace an existing one */
00153 static void node_socket_add_replace(Main *bmain, bNodeTree *ntree, bNode *node_to, bNodeSocket *sock_to, bNodeTemplate *ntemp, int sock_num)
00154 {
00155     bNode *node_from;
00156     bNodeSocket *sock_from;
00157     bNode *node_prev = NULL;
00158 
00159     /* unlink existing node */
00160     if(sock_to->link) {
00161         node_prev = sock_to->link->fromnode;
00162         nodeRemLink(ntree, sock_to->link);
00163     }
00164 
00165     /* find existing node that we can use */
00166     for(node_from=ntree->nodes.first; node_from; node_from=node_from->next)
00167         if(node_from->type == ntemp->type)
00168             break;
00169 
00170     if(node_from)
00171         if(!(node_from->inputs.first == NULL && !(node_from->typeinfo->flag & NODE_OPTIONS)))
00172             node_from = NULL;
00173 
00174     if(node_prev && node_prev->type == ntemp->type &&
00175         (ntemp->type != NODE_GROUP || node_prev->id == &ntemp->ngroup->id)) {
00176         /* keep the previous node if it's the same type */
00177         node_from = node_prev;
00178     }
00179     else if(!node_from) {
00180         node_from= nodeAddNode(ntree, ntemp);
00181         node_from->locx = node_to->locx - (node_from->typeinfo->width + 50);
00182         node_from->locy = node_to->locy;
00183 
00184         if(node_from->id)
00185             id_us_plus(node_from->id);
00186     }
00187 
00188     nodeSetActive(ntree, node_from);
00189 
00190     /* add link */
00191     sock_from = BLI_findlink(&node_from->outputs, sock_num);
00192     nodeAddLink(ntree, node_from, sock_from, node_to, sock_to);
00193 
00194     /* copy input sockets from previous node */
00195     if(node_prev && node_from != node_prev) {
00196         bNodeSocket *sock_prev, *sock_from;
00197 
00198         for(sock_prev=node_prev->inputs.first; sock_prev; sock_prev=sock_prev->next) {
00199             for(sock_from=node_from->inputs.first; sock_from; sock_from=sock_from->next) {
00200                 if(strcmp(sock_prev->name, sock_from->name) == 0 && sock_prev->type == sock_from->type) {
00201                     bNodeLink *link = sock_prev->link;
00202 
00203                     if(link && link->fromnode) {
00204                         nodeAddLink(ntree, link->fromnode, link->fromsock, node_from, sock_from);
00205                         nodeRemLink(ntree, link);
00206                     }
00207 
00208                     if(sock_prev->default_value) {
00209                         if(sock_from->default_value)
00210                             MEM_freeN(sock_from->default_value);
00211 
00212                         sock_from->default_value = MEM_dupallocN(sock_prev->default_value);
00213                     }
00214                 }
00215             }
00216         }
00217 
00218         /* also preserve mapping for texture nodes */
00219         if(node_from->typeinfo->nclass == NODE_CLASS_TEXTURE &&
00220            node_prev->typeinfo->nclass == NODE_CLASS_TEXTURE)
00221             memcpy(node_from->storage, node_prev->storage, sizeof(NodeTexBase));
00222 
00223         /* remove node */
00224         node_remove_linked(ntree, node_prev);
00225     }
00226 
00227     nodeUpdate(ntree, node_from);
00228     nodeUpdate(ntree, node_to);
00229     ntreeUpdateTree(ntree);
00230 
00231     ED_node_generic_update(bmain, ntree, node_to);
00232 }
00233 
00234 /****************************** Node Link Menu *******************************/
00235 
00236 #define UI_NODE_LINK_ADD        0
00237 #define UI_NODE_LINK_DISCONNECT -1
00238 #define UI_NODE_LINK_REMOVE     -2
00239 
00240 typedef struct NodeLinkArg {
00241     Main *bmain;
00242     Scene *scene;
00243     bNodeTree *ntree;
00244     bNode *node;
00245     bNodeSocket *sock;
00246 
00247     bNodeTree *ngroup;
00248     int type;
00249     int output;
00250 
00251     uiLayout *layout;
00252 } NodeLinkArg;
00253 
00254 static void ui_node_link(bContext *UNUSED(C), void *arg_p, void *event_p)
00255 {
00256     NodeLinkArg *arg = (NodeLinkArg*)arg_p;
00257     Main *bmain = arg->bmain;
00258     bNode *node_to = arg->node;
00259     bNodeSocket *sock_to = arg->sock;
00260     bNodeTree *ntree = arg->ntree;
00261     int event = GET_INT_FROM_POINTER(event_p);
00262     bNodeTemplate ntemp;
00263 
00264     ntemp.type = arg->type;
00265     ntemp.ngroup = arg->ngroup;
00266 
00267     if(event == UI_NODE_LINK_DISCONNECT)
00268         node_socket_disconnect(bmain, ntree, node_to, sock_to);
00269     else if(event == UI_NODE_LINK_REMOVE)
00270         node_socket_remove(bmain, ntree, node_to, sock_to);
00271     else
00272         node_socket_add_replace(bmain, ntree, node_to, sock_to, &ntemp, arg->output);
00273 }
00274 
00275 static void ui_node_sock_name(bNodeSocket *sock, char name[UI_MAX_NAME_STR])
00276 {
00277     if(sock->link && sock->link->fromnode) {
00278         bNode *node = sock->link->fromnode;
00279         char node_name[UI_MAX_NAME_STR];
00280 
00281         if(node->type == NODE_GROUP)
00282             BLI_strncpy(node_name, node->id->name+2, UI_MAX_NAME_STR);
00283         else
00284             BLI_strncpy(node_name, node->typeinfo->name, UI_MAX_NAME_STR);
00285 
00286         if(node->inputs.first == NULL &&
00287            node->outputs.first != node->outputs.last &&
00288            !(node->typeinfo->flag & NODE_OPTIONS))
00289             BLI_snprintf(name, UI_MAX_NAME_STR, "%s | %s", node_name, sock->link->fromsock->name);
00290         else
00291             BLI_strncpy(name, node_name, UI_MAX_NAME_STR);
00292     }
00293     else if(sock->type == SOCK_SHADER)
00294         BLI_strncpy(name, "None", UI_MAX_NAME_STR);
00295     else
00296         BLI_strncpy(name, "Default", UI_MAX_NAME_STR);
00297 }
00298 
00299 static int ui_compatible_sockets(int typeA, int typeB)
00300 {
00301     return (typeA == typeB);
00302 }
00303 
00304 static void ui_node_menu_column(NodeLinkArg *arg, int nclass, const char *cname)
00305 {
00306     Main *bmain = arg->bmain;
00307     bNodeTree *ntree = arg->ntree;
00308     bNodeSocket *sock = arg->sock;
00309     uiLayout *layout = arg->layout;
00310     uiLayout *column = NULL;
00311     uiBlock *block = uiLayoutGetBlock(layout);
00312     uiBut *but;
00313     bNodeType *ntype;
00314     bNodeTree *ngroup;
00315     NodeLinkArg *argN;
00316     int first = 1;
00317     int compatibility= 0;
00318 
00319     if(ntree->type == NTREE_SHADER) {
00320         if(scene_use_new_shading_nodes(arg->scene))
00321             compatibility= NODE_NEW_SHADING;
00322         else
00323             compatibility= NODE_OLD_SHADING;
00324     }
00325 
00326     if(nclass == NODE_CLASS_GROUP) {
00327         for(ngroup=bmain->nodetree.first; ngroup; ngroup=ngroup->id.next) {
00328             bNodeSocket *gsock;
00329             char name[UI_MAX_NAME_STR];
00330             int i, j, num = 0;
00331 
00332             if(ngroup->type != ntree->type)
00333                 continue;
00334 
00335             for(gsock=ngroup->inputs.first; gsock; gsock=gsock->next)
00336                 if(ui_compatible_sockets(gsock->type, sock->type))
00337                     num++;
00338 
00339             for(i=0, j=0, gsock=ngroup->outputs.first; gsock; gsock=gsock->next, i++) {
00340                 if(!ui_compatible_sockets(gsock->type, sock->type))
00341                     continue;
00342 
00343                 if(first) {
00344                     column= uiLayoutColumn(layout, 0);
00345                     uiBlockSetCurLayout(block, column);
00346 
00347                     uiItemL(column, cname, ICON_NODE);
00348                     but= block->buttons.last;
00349                     but->flag= UI_TEXT_LEFT;
00350 
00351                     first = 0;
00352                 }
00353 
00354                 if(num > 1) {
00355                     if(j == 0) {
00356                         uiItemL(column, ngroup->id.name+2, ICON_NODE);
00357                         but= block->buttons.last;
00358                         but->flag= UI_TEXT_LEFT;
00359                     }
00360 
00361                     BLI_snprintf(name, UI_MAX_NAME_STR, "  %s", gsock->name);
00362                     j++;
00363                 }
00364                 else
00365                     BLI_strncpy(name, ngroup->id.name+2, UI_MAX_NAME_STR);
00366 
00367                 but = uiDefBut(block, BUT, 0, ngroup->id.name+2, 0, 0, UI_UNIT_X*4, UI_UNIT_Y,
00368                     NULL, 0.0, 0.0, 0.0, 0.0, "Add node to input");
00369 
00370                 argN = MEM_dupallocN(arg);
00371                 argN->type = NODE_GROUP;
00372                 argN->ngroup = ngroup;
00373                 argN->output = i;
00374                 uiButSetNFunc(but, ui_node_link, argN, NULL);
00375             }
00376         }
00377     }
00378     else {
00379         bNodeTreeType *ttype= ntreeGetType(ntree->type);
00380 
00381         for(ntype=ttype->node_types.first; ntype; ntype=ntype->next) {
00382             bNodeSocketTemplate *stemp;
00383             char name[UI_MAX_NAME_STR];
00384             int i, j, num = 0;
00385 
00386             if(compatibility && !(ntype->compatibility & compatibility))
00387                 continue;
00388 
00389             if(ntype->nclass != nclass)
00390                 continue;
00391 
00392             for(i=0, stemp=ntype->outputs; stemp && stemp->type != -1; stemp++, i++)
00393                 if(ui_compatible_sockets(stemp->type, sock->type))
00394                     num++;
00395 
00396             for(i=0, j=0, stemp=ntype->outputs; stemp && stemp->type != -1; stemp++, i++) {
00397                 if(!ui_compatible_sockets(stemp->type, sock->type))
00398                     continue;
00399 
00400                 if(first) {
00401                     column= uiLayoutColumn(layout, 0);
00402                     uiBlockSetCurLayout(block, column);
00403 
00404                     uiItemL(column, cname, ICON_NODE);
00405                     but= block->buttons.last;
00406                     but->flag= UI_TEXT_LEFT;
00407 
00408                     first = 0;
00409                 }
00410 
00411                 if(num > 1) {
00412                     if(j == 0) {
00413                         uiItemL(column, ntype->name, ICON_NODE);
00414                         but= block->buttons.last;
00415                         but->flag= UI_TEXT_LEFT;
00416                     }
00417 
00418                     BLI_snprintf(name, UI_MAX_NAME_STR, "  %s", stemp->name);
00419                     j++;
00420                 }
00421                 else
00422                     BLI_strncpy(name, ntype->name, UI_MAX_NAME_STR);
00423 
00424                 but = uiDefBut(block, BUT, 0, name, 0, 0, UI_UNIT_X*4, UI_UNIT_Y,
00425                     NULL, 0.0, 0.0, 0.0, 0.0, "Add node to input");
00426 
00427                 argN = MEM_dupallocN(arg);
00428                 argN->type = ntype->type;
00429                 argN->output = i;
00430                 uiButSetNFunc(but, ui_node_link, argN, NULL);
00431             }
00432         }
00433     }
00434 }
00435 
00436 static void node_menu_column_foreach_cb(void *calldata, int nclass, const char *name)
00437 {
00438     NodeLinkArg *arg = (NodeLinkArg*)calldata;
00439 
00440     if(!ELEM(nclass, NODE_CLASS_GROUP, NODE_CLASS_LAYOUT))
00441         ui_node_menu_column(arg, nclass, name);
00442 }
00443 
00444 static void ui_template_node_link_menu(bContext *C, uiLayout *layout, void *but_p)
00445 {
00446     Main *bmain= CTX_data_main(C);
00447     Scene *scene= CTX_data_scene(C);
00448     uiBlock *block = uiLayoutGetBlock(layout);
00449     uiBut *but = (uiBut*)but_p;
00450     uiLayout *split, *column;
00451     NodeLinkArg *arg = (NodeLinkArg*)but->func_argN;
00452     bNodeSocket *sock = arg->sock;
00453     bNodeTreeType *ntreetype= ntreeGetType(arg->ntree->type);
00454 
00455     uiBlockSetCurLayout(block, layout);
00456     split= uiLayoutSplit(layout, 0, 0);
00457 
00458     arg->bmain= bmain;
00459     arg->scene= scene;
00460     arg->layout= split;
00461     
00462     if(ntreetype && ntreetype->foreach_nodeclass)
00463         ntreetype->foreach_nodeclass(scene, arg, node_menu_column_foreach_cb);
00464 
00465     column= uiLayoutColumn(split, 0);
00466     uiBlockSetCurLayout(block, column);
00467 
00468     if(sock->link) {
00469         uiItemL(column, "Link", ICON_NONE);
00470         but= block->buttons.last;
00471         but->flag= UI_TEXT_LEFT;
00472 
00473         but = uiDefBut(block, BUT, 0, "Remove", 0, 0, UI_UNIT_X*4, UI_UNIT_Y,
00474             NULL, 0.0, 0.0, 0.0, 0.0, "Remove nodes connected to the input");
00475         uiButSetNFunc(but, ui_node_link, MEM_dupallocN(arg), SET_INT_IN_POINTER(UI_NODE_LINK_REMOVE));
00476 
00477         but = uiDefBut(block, BUT, 0, "Disconnect", 0, 0, UI_UNIT_X*4, UI_UNIT_Y,
00478             NULL, 0.0, 0.0, 0.0, 0.0, "Disconnect nodes connected to the input");
00479         uiButSetNFunc(but, ui_node_link, MEM_dupallocN(arg), SET_INT_IN_POINTER(UI_NODE_LINK_DISCONNECT));
00480     }
00481 
00482     ui_node_menu_column(arg, NODE_CLASS_GROUP, IFACE_("Group"));
00483 }
00484 
00485 void uiTemplateNodeLink(uiLayout *layout, bNodeTree *ntree, bNode *node, bNodeSocket *sock)
00486 {
00487     uiBlock *block = uiLayoutGetBlock(layout);
00488     NodeLinkArg *arg;
00489     uiBut *but;
00490 
00491     arg = MEM_callocN(sizeof(NodeLinkArg), "NodeLinkArg");
00492     arg->ntree = ntree;
00493     arg->node = node;
00494     arg->sock = sock;
00495     arg->type = 0;
00496     arg->output = 0;
00497 
00498     uiBlockSetCurLayout(block, layout);
00499 
00500     if(sock->link || sock->type == SOCK_SHADER || (sock->flag & SOCK_HIDE_VALUE)) {
00501         char name[UI_MAX_NAME_STR];
00502         ui_node_sock_name(sock, name);
00503         but= uiDefMenuBut(block, ui_template_node_link_menu, NULL, name, 0, 0, UI_UNIT_X*4, UI_UNIT_Y, "");
00504     }
00505     else
00506         but= uiDefIconMenuBut(block, ui_template_node_link_menu, NULL, ICON_NONE, 0, 0, UI_UNIT_X, UI_UNIT_Y, "");
00507 
00508     but->type= MENU;
00509     but->flag |= UI_TEXT_LEFT|UI_BUT_NODE_LINK;
00510     but->poin= (char*)but;
00511     but->func_argN = arg;
00512 
00513     if(sock->link && sock->link->fromnode)
00514         if(sock->link->fromnode->flag & NODE_ACTIVE_TEXTURE)
00515             but->flag |= UI_BUT_NODE_ACTIVE;
00516 }
00517 
00518 /**************************** Node Tree Layout *******************************/
00519 
00520 static void ui_node_draw_input(uiLayout *layout, bContext *C,
00521     bNodeTree *ntree, bNode *node, bNodeSocket *input, int depth);
00522 
00523 static void ui_node_draw_node(uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, int depth)
00524 {
00525     bNodeSocket *input;
00526     uiLayout *col, *split;
00527     PointerRNA nodeptr;
00528 
00529     RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr);
00530 
00531     if(node->typeinfo->uifunc) {
00532         if(node->type != NODE_GROUP) {
00533             split = uiLayoutSplit(layout, 0.35f, 0);
00534             col = uiLayoutColumn(split, 0);
00535             col = uiLayoutColumn(split, 0);
00536 
00537             node->typeinfo->uifunc(col, C, &nodeptr);
00538         }
00539     }
00540 
00541     for(input=node->inputs.first; input; input=input->next)
00542         ui_node_draw_input(layout, C, ntree, node, input, depth+1);
00543 }
00544 
00545 static void ui_node_draw_input(uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *input, int depth)
00546 {
00547     PointerRNA inputptr;
00548     uiBlock *block = uiLayoutGetBlock(layout);
00549     uiBut *bt;
00550     uiLayout *split, *row, *col;
00551     bNode *lnode;
00552     char label[UI_MAX_NAME_STR];
00553     int indent = (depth > 1)? 2*(depth - 1): 0;
00554     int dependency_loop;
00555 
00556     if(input->flag & SOCK_UNAVAIL)
00557         return;
00558 
00559     /* to avoid eternal loops on cyclic dependencies */
00560     node->flag |= NODE_TEST;
00561     lnode = (input->link)? input->link->fromnode: NULL;
00562 
00563     dependency_loop = (lnode && (lnode->flag & NODE_TEST));
00564     if(dependency_loop)
00565         lnode = NULL;
00566 
00567     /* socket RNA pointer */
00568     RNA_pointer_create(&ntree->id, &RNA_NodeSocket, input, &inputptr);
00569 
00570     /* indented label */
00571     memset(label, ' ', indent);
00572     label[indent] = '\0';
00573     BLI_snprintf(label, UI_MAX_NAME_STR, "%s%s:", label, input->name);
00574 
00575     /* split in label and value */
00576     split = uiLayoutSplit(layout, 0.35f, 0);
00577 
00578     row = uiLayoutRow(split, 1);
00579 
00580     if(depth > 0) {
00581         uiBlockSetEmboss(block, UI_EMBOSSN);
00582 
00583         if(lnode && (lnode->inputs.first || (lnode->typeinfo->uifunc && lnode->type != NODE_GROUP))) {
00584             int icon = (input->flag & SOCK_COLLAPSED)? ICON_DISCLOSURE_TRI_RIGHT: ICON_DISCLOSURE_TRI_DOWN;
00585             uiItemR(row, &inputptr, "show_expanded", UI_ITEM_R_ICON_ONLY, "", icon);
00586         }
00587         else
00588             uiItemL(row, "", ICON_BLANK1);
00589 
00590         bt = block->buttons.last;
00591         bt->x2 = UI_UNIT_X/2;
00592 
00593         uiBlockSetEmboss(block, UI_EMBOSS);
00594     }
00595 
00596     uiItemL(row, label, ICON_NONE);
00597     bt= block->buttons.last;
00598     bt->flag= UI_TEXT_LEFT;
00599 
00600     if(dependency_loop) {
00601         row = uiLayoutRow(split, 0);
00602         uiItemL(row, "Dependency Loop", ICON_ERROR);
00603     }
00604     else if(lnode) {
00605         /* input linked to a node */
00606         uiTemplateNodeLink(split, ntree, node, input);
00607 
00608         if(!(input->flag & SOCK_COLLAPSED)) {
00609             if(depth == 0)
00610                 uiItemS(layout);
00611 
00612             ui_node_draw_node(layout, C, ntree, lnode, depth);
00613         }
00614     }
00615     else {
00616         /* input not linked, show value */
00617         if(input->type != SOCK_SHADER && !(input->flag & SOCK_HIDE_VALUE)) {
00618             if(input->type == SOCK_VECTOR) {
00619                 row = uiLayoutRow(split, 0);
00620                 col = uiLayoutColumn(row, 0);
00621 
00622                 uiItemR(col, &inputptr, "default_value", 0, "", 0);
00623             }
00624             else {
00625                 row = uiLayoutRow(split, 1);
00626                 uiItemR(row, &inputptr, "default_value", 0, "", 0);
00627             }
00628         }
00629         else
00630             row = uiLayoutRow(split, 0);
00631 
00632         uiTemplateNodeLink(row, ntree, node, input);
00633     }
00634 
00635     /* clear */
00636     node->flag &= ~NODE_TEST;
00637 }
00638 
00639 void uiTemplateNodeView(uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *input)
00640 {
00641     bNode *tnode;
00642 
00643     if(!ntree)
00644         return;
00645 
00646     /* clear for cycle check */
00647     for(tnode=ntree->nodes.first; tnode; tnode=tnode->next)
00648         tnode->flag &= ~NODE_TEST;
00649 
00650     if(input)
00651         ui_node_draw_input(layout, C, ntree, node, input, 0);
00652     else
00653         ui_node_draw_node(layout, C, ntree, node, 0);
00654 }
00655