UI/Nodes: templates to edit nodes from the properties editor using a tree view,
authorBrecht Van Lommel <brechtvanlommel@pandora.be>
Mon, 7 Nov 2011 22:28:49 +0000 (22:28 +0000)
committerBrecht Van Lommel <brechtvanlommel@pandora.be>
Mon, 7 Nov 2011 22:28:49 +0000 (22:28 +0000)
to be used by cycles. For testing there's a panel in the node editor if you set
debug to 777, didn't enable it because I'm not sure it's very useful there.

source/blender/editors/include/UI_interface.h
source/blender/editors/interface/interface_intern.h
source/blender/editors/interface/interface_regions.c
source/blender/editors/interface/interface_widgets.c
source/blender/editors/space_node/CMakeLists.txt
source/blender/editors/space_node/node_buttons.c
source/blender/editors/space_node/node_templates.c [new file with mode: 0644]
source/blender/makesrna/intern/rna_ui_api.c
source/blenderplayer/bad_level_call_stubs/stubs.c

index 942252bc00ff608c4c6ccf107387f4bcd2c9b365..02b8cc9e2c65e8e9733b82b9e0305c173f817661 100644 (file)
@@ -66,6 +66,9 @@ struct uiWidgetColors;
 struct Tex;
 struct MTex;
 struct ImBuf;
+struct bNodeTree;
+struct bNode;
+struct bNodeSocket;
 
 typedef struct uiBut uiBut;
 typedef struct uiBlock uiBlock;
@@ -74,6 +77,10 @@ typedef struct uiLayout uiLayout;
 
 /* Defines */
 
+/* names */
+#define UI_MAX_DRAW_STR        400
+#define UI_MAX_NAME_STR        128
+
 /* uiBlock->dt */
 #define UI_EMBOSS              0       /* use widget style for drawing */
 #define UI_EMBOSSN             1       /* Nothing, only icon and/or text */
@@ -128,11 +135,11 @@ typedef struct uiLayout uiLayout;
 #define UI_ICON_LEFT   128
 #define UI_ICON_SUBMENU        256
 #define UI_ICON_PREVIEW        512
-       /* control for button type block */
-#define UI_MAKE_TOP            1024
-#define UI_MAKE_DOWN   2048
-#define UI_MAKE_LEFT   4096
-#define UI_MAKE_RIGHT  8192
+
+#define UI_TEXT_RIGHT          1024
+#define UI_BUT_NODE_LINK       2048
+#define UI_BUT_NODE_ACTIVE     4096
+#define UI_FLAG_UNUSED         8192
 
        /* button align flag, for drawing groups together */
 #define UI_BUT_ALIGN           (UI_BUT_ALIGN_TOP|UI_BUT_ALIGN_LEFT|UI_BUT_ALIGN_RIGHT|UI_BUT_ALIGN_DOWN)
@@ -749,6 +756,8 @@ void uiTemplateReportsBanner(uiLayout *layout, struct bContext *C);
 void uiTemplateKeymapItemProperties(uiLayout *layout, struct PointerRNA *ptr);
 
 void uiTemplateList(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, struct PointerRNA *activeptr, const char *activeprop, const char *prop_list, int rows, int maxrows, int type);
+void uiTemplateNodeLink(uiLayout *layout, struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *input);
+void uiTemplateNodeView(uiLayout *layout, struct bContext *C, struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *input);
 
 void uiTemplateMovieClip(struct uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, int compact);
 void uiTemplateTrack(struct uiLayout *layout, struct PointerRNA *ptr, const char *propname);
index 29447d492c5bd9a389a4da11e1e4af7d3e0e3ebd..aa4158ad4b7c95787d8421ee8a3c18e0e75722bc 100644 (file)
@@ -79,6 +79,7 @@ typedef enum {
        UI_WTYPE_MENU_RADIO,
        UI_WTYPE_MENU_ICON_RADIO,
        UI_WTYPE_MENU_POINTER_LINK,
+       UI_WTYPE_MENU_NODE_LINK,
        
        UI_WTYPE_PULLDOWN,
        UI_WTYPE_MENU_ITEM,
@@ -96,11 +97,6 @@ typedef enum {
        
 } uiWidgetTypeEnum;
 
-
-
-#define UI_MAX_DRAW_STR        400
-#define UI_MAX_NAME_STR        128
-
 /* panel limits */
 #define UI_PANEL_MINX  100
 #define UI_PANEL_MINY  70
index edbd5c5684e83e57ef76948a57fd49858dbabebe..34b62155314dcff5a74fb029e35e6c089a73c160 100644 (file)
@@ -1533,15 +1533,6 @@ uiPopupBlockHandle *ui_popup_block_create(bContext *C, ARegion *butregion, uiBut
                if(ELEM(but->type, BLOCK, PULLDOWN))
                        block->xofs = -2;       /* for proper alignment */
 
-               /* only used for automatic toolbox, so can set the shift flag */
-               if(but->flag & UI_MAKE_TOP) {
-                       block->direction= UI_TOP|UI_SHIFT_FLIPPED;
-                       uiBlockFlipOrder(block);
-               }
-               if(but->flag & UI_MAKE_DOWN) block->direction= UI_DOWN|UI_SHIFT_FLIPPED;
-               if(but->flag & UI_MAKE_LEFT) block->direction |= UI_LEFT;
-               if(but->flag & UI_MAKE_RIGHT) block->direction |= UI_RIGHT;
-
                ui_block_position(window, butregion, but, block);
        }
        else {
index 8ab48ac8ffa1e6c16ef8a6f6988a154f0ba99970..aa407bbf6d4f780cbd0bca015f76317834967a0f 100644 (file)
@@ -1181,6 +1181,12 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB
                        
                        widget_draw_icon(but, ICON_DOT, dualset?1.0f:0.25f, rect);
                }
+               else if(but->type==MENU && (but->flag & UI_BUT_NODE_LINK)) {
+                       int tmp = rect->xmin;
+                       rect->xmin = rect->xmax - (rect->ymax - rect->ymin) - 1;
+                       widget_draw_icon(but, ICON_LAYER_USED, 1.0f, rect);
+                       rect->xmin = tmp;
+               }
                
                /* If there's an icon too (made with uiDefIconTextBut) then draw the icon
                and offset the text label to accommodate it */
@@ -1543,6 +1549,10 @@ static void widget_state(uiWidgetType *wt, int state)
                char red[4]= {255, 0, 0};
                widget_state_blend(wt->wcol.inner, red, 0.4f);
        }
+       if(state & UI_BUT_NODE_ACTIVE) {
+               char blue[4]= {86, 128, 194};
+               widget_state_blend(wt->wcol.inner, blue, 0.3f);
+       }
 }
 
 /* sliders use special hack which sets 'item' as inner when drawing filling */
@@ -2530,6 +2540,29 @@ static void widget_menuiconbut(uiWidgetColors *wcol, rcti *rect, int UNUSED(stat
        widgetbase_draw(&wtb, wcol);
 }
 
+static void widget_menunodebut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
+{
+       /* silly node link button hacks */
+       uiWidgetBase wtb;
+       uiWidgetColors wcol_backup= *wcol;
+       
+       widget_init(&wtb);
+       
+       /* half rounded */
+       round_box_edges(&wtb, roundboxalign, rect, 4.0f);
+
+       wcol->inner[0] += 15;
+       wcol->inner[1] += 15;
+       wcol->inner[2] += 15;
+       wcol->outline[0] += 15;
+       wcol->outline[1] += 15;
+       wcol->outline[2] += 15;
+       
+       /* decoration */
+       widgetbase_draw(&wtb, wcol);
+       *wcol= wcol_backup;
+}
+
 static void widget_pulldownbut(uiWidgetColors *wcol, rcti *rect, int state, int UNUSED(roundboxalign))
 {
        if(state & UI_ACTIVE) {
@@ -2804,6 +2837,11 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type)
                        wt.wcol_theme= &btheme->tui.wcol_menu;
                        wt.draw= widget_menubut;
                        break;
+
+               case UI_WTYPE_MENU_NODE_LINK:
+                       wt.wcol_theme= &btheme->tui.wcol_menu;
+                       wt.draw= widget_menunodebut;
+                       break;
                        
                case UI_WTYPE_PULLDOWN:
                        wt.wcol_theme= &btheme->tui.wcol_pulldown;
@@ -2996,7 +3034,9 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
                        case MENU:
                        case BLOCK:
                        case ICONTEXTROW:
-                               if(!but->str[0] && but->icon)
+                               if(but->flag & UI_BUT_NODE_LINK)
+                                       wt= widget_type(UI_WTYPE_MENU_NODE_LINK);
+                               else if(!but->str[0] && but->icon)
                                        wt= widget_type(UI_WTYPE_MENU_ICON_RADIO);
                                else
                                        wt= widget_type(UI_WTYPE_MENU_RADIO);
index 8a27bcca8af488da91ec1cb02d39b7a920043473..991b35585a608ee63d1911c837d8969af11860d3 100644 (file)
@@ -47,6 +47,7 @@ set(SRC
        node_ops.c
        node_select.c
        node_state.c
+       node_templates.c
        space_node.c
 
        node_intern.h
index 3886c70919666fa95fd96b5fa73a00aed1068017..15e5719be37250f784244b30f078640b8ec8edcd 100644 (file)
@@ -45,6 +45,7 @@
 #include "BLI_utildefines.h"
 
 #include "BKE_context.h"
+#include "BKE_global.h"
 #include "BKE_node.h"
 #include "BKE_screen.h"
 
@@ -122,6 +123,34 @@ static void active_node_panel(const bContext *C, Panel *pa)
                node->typeinfo->uifunc(layout, (bContext *)C, &ptr);
 }
 
+static int node_sockets_poll(const bContext *C, PanelType *UNUSED(pt))
+{
+       SpaceNode *snode= CTX_wm_space_node(C);
+       
+       return (snode && snode->nodetree && G.rt == 777);
+}
+
+static void node_sockets_panel(const bContext *C, Panel *pa)
+{
+       SpaceNode *snode= CTX_wm_space_node(C);
+       bNodeTree *ntree= (snode) ? snode->edittree : NULL;
+       bNode *node = (ntree) ? nodeGetActive(ntree) : NULL;
+       bNodeSocket *sock;
+       uiLayout *layout= pa->layout, *split;
+       char name[UI_MAX_NAME_STR];
+       
+       if(ELEM(NULL, ntree, node))
+               return;
+       
+       for(sock=node->inputs.first; sock; sock=sock->next) {
+               BLI_snprintf(name, sizeof(name), "%s:", sock->name);
+
+               split = uiLayoutSplit(layout, 0.35f, 0);
+               uiItemL(split, name, ICON_NONE);
+               uiTemplateNodeLink(split, ntree, node, sock);
+       }
+}
+
 /* ******************* node buttons registration ************** */
 
 void node_buttons_register(ARegionType *art)
@@ -134,6 +163,14 @@ void node_buttons_register(ARegionType *art)
        pt->draw= active_node_panel;
        pt->poll= active_node_poll;
        BLI_addtail(&art->paneltypes, pt);
+
+       pt= MEM_callocN(sizeof(PanelType), "spacetype node panel node sockets");
+       strcpy(pt->idname, "NODE_PT_sockets");
+       strcpy(pt->label, "Sockets");
+       pt->draw= node_sockets_panel;
+       pt->poll= node_sockets_poll;
+       pt->flag |= PNL_DEFAULT_CLOSED;
+       BLI_addtail(&art->paneltypes, pt);
        
        pt= MEM_callocN(sizeof(PanelType), "spacetype node panel gpencil");
        strcpy(pt->idname, "NODE_PT_gpencil");
diff --git a/source/blender/editors/space_node/node_templates.c b/source/blender/editors/space_node/node_templates.c
new file mode 100644 (file)
index 0000000..b877bea
--- /dev/null
@@ -0,0 +1,636 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Foundation 2009.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/interface/interface_node.c
+ *  \ingroup edinterface
+ */
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_node_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_depsgraph.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_node.h"
+#include "BKE_scene.h"
+
+#include "RNA_access.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+#include "../interface/interface_intern.h"
+
+#include "ED_node.h"
+
+/************************* Node Socket Manipulation **************************/
+
+static void node_tag_recursive(bNode *node)
+{
+       bNodeSocket *input;
+
+       if(!node || (node->flag & NODE_TEST))
+               return; /* in case of cycles */
+       
+       node->flag |= NODE_TEST;
+
+       for(input=node->inputs.first; input; input=input->next)
+               if(input->link)
+                       node_tag_recursive(input->link->fromnode);
+}
+
+static void node_clear_recursive(bNode *node)
+{
+       bNodeSocket *input;
+
+       if(!node || !(node->flag & NODE_TEST))
+               return; /* in case of cycles */
+       
+       node->flag &= ~NODE_TEST;
+
+       for(input=node->inputs.first; input; input=input->next)
+               if(input->link)
+                       node_clear_recursive(input->link->fromnode);
+}
+
+static void node_remove_linked(bNodeTree *ntree, bNode *rem_node)
+{
+       bNode *node, *next;
+       bNodeSocket *sock;
+
+       if(!rem_node)
+               return;
+
+       /* tag linked nodes to be removed */
+       for(node=ntree->nodes.first; node; node=node->next)
+               node->flag &= ~NODE_TEST;
+       
+       node_tag_recursive(rem_node);
+
+       /* clear tags on nodes that are still used by other nodes */
+       for(node=ntree->nodes.first; node; node=node->next)
+               if(!(node->flag & NODE_TEST))
+                       for(sock=node->inputs.first; sock; sock=sock->next)
+                               if(sock->link && sock->link->fromnode != rem_node)
+                                       node_clear_recursive(sock->link->fromnode);
+
+       /* remove nodes */
+       for(node=ntree->nodes.first; node; node=next) {
+               next = node->next;
+
+               if(node->flag & NODE_TEST) {
+                       if(node->id)
+                               node->id->us--;
+                       nodeFreeNode(ntree, node);
+               }
+       }
+}
+
+/* disconnect socket from the node it is connected to */
+static void node_socket_disconnect(Main *bmain, bNodeTree *ntree, bNode *node_to, bNodeSocket *sock_to)
+{
+       if(!sock_to->link)
+               return;
+
+       nodeRemLink(ntree, sock_to->link);
+
+       nodeUpdate(ntree, node_to);
+       ntreeUpdateTree(ntree);
+
+       ED_node_generic_update(bmain, ntree, node_to);
+}
+
+/* remove all nodes connected to this socket, if they aren't connected to other nodes */
+static void node_socket_remove(Main *bmain, bNodeTree *ntree, bNode *node_to, bNodeSocket *sock_to)
+{
+       if(!sock_to->link)
+               return;
+
+       node_remove_linked(ntree, sock_to->link->fromnode);
+
+       nodeUpdate(ntree, node_to);
+       ntreeUpdateTree(ntree);
+
+       ED_node_generic_update(bmain, ntree, node_to);
+}
+
+/* add new node connected to this socket, or replace an existing one */
+static void node_socket_add_replace(Main *bmain, bNodeTree *ntree, bNode *node_to, bNodeSocket *sock_to, bNodeTemplate *ntemp, int sock_num)
+{
+       bNode *node_from;
+       bNodeSocket *sock_from;
+       bNode *node_prev = NULL;
+
+       /* unlink existing node */
+       if(sock_to->link) {
+               node_prev = sock_to->link->fromnode;
+               nodeRemLink(ntree, sock_to->link);
+       }
+
+       /* find existing node that we can use */
+       for(node_from=ntree->nodes.first; node_from; node_from=node_from->next)
+               if(node_from->type == ntemp->type)
+                       break;
+
+       if(node_from)
+               if(!(node_from->inputs.first == NULL && !(node_from->typeinfo->flag & NODE_OPTIONS)))
+                       node_from = NULL;
+
+       if(node_prev && node_prev->type == ntemp->type &&
+               (ntemp->type != NODE_GROUP || node_prev->id == &ntemp->ngroup->id)) {
+               /* keep the previous node if it's the same type */
+               node_from = node_prev;
+       }
+       else if(!node_from) {
+               node_from= nodeAddNode(ntree, ntemp);
+               node_from->locx = node_to->locx - (node_from->typeinfo->width + 50);
+               node_from->locy = node_to->locy;
+
+               if(node_from->id)
+                       id_us_plus(node_from->id);
+       }
+
+       nodeSetActive(ntree, node_from);
+
+       /* add link */
+       sock_from = BLI_findlink(&node_from->outputs, sock_num);
+       nodeAddLink(ntree, node_from, sock_from, node_to, sock_to);
+
+       /* copy input sockets from previous node */
+       if(node_prev && node_from != node_prev) {
+               bNodeSocket *sock_prev, *sock_from;
+
+               for(sock_prev=node_prev->inputs.first; sock_prev; sock_prev=sock_prev->next) {
+                       for(sock_from=node_from->inputs.first; sock_from; sock_from=sock_from->next) {
+                               if(strcmp(sock_prev->name, sock_from->name) == 0 && sock_prev->type == sock_from->type) {
+                                       bNodeLink *link = sock_prev->link;
+
+                                       if(link && link->fromnode) {
+                                               nodeAddLink(ntree, link->fromnode, link->fromsock, node_from, sock_from);
+                                               nodeRemLink(ntree, link);
+                                       }
+
+                                       if(sock_prev->default_value) {
+                                               if(sock_from->default_value)
+                                                       MEM_freeN(sock_from->default_value);
+
+                                               sock_from->default_value = MEM_dupallocN(sock_prev->default_value);
+                                       }
+                               }
+                       }
+               }
+
+               /* remove node */
+               node_remove_linked(ntree, node_prev);
+       }
+
+       nodeUpdate(ntree, node_from);
+       nodeUpdate(ntree, node_to);
+       ntreeUpdateTree(ntree);
+
+       ED_node_generic_update(bmain, ntree, node_to);
+}
+
+/****************************** Node Link Menu *******************************/
+
+#define UI_NODE_LINK_ADD               0
+#define UI_NODE_LINK_DISCONNECT        -1
+#define UI_NODE_LINK_REMOVE            -2
+
+typedef struct NodeLinkArg {
+       Main *bmain;
+       Scene *scene;
+       bNodeTree *ntree;
+       bNode *node;
+       bNodeSocket *sock;
+
+       bNodeTree *ngroup;
+       int type;
+       int output;
+
+       uiLayout *layout;
+} NodeLinkArg;
+
+static void ui_node_link(bContext *UNUSED(C), void *arg_p, void *event_p)
+{
+       NodeLinkArg *arg = (NodeLinkArg*)arg_p;
+       Main *bmain = arg->bmain;
+       bNode *node_to = arg->node;
+       bNodeSocket *sock_to = arg->sock;
+       bNodeTree *ntree = arg->ntree;
+       int event = GET_INT_FROM_POINTER(event_p);
+       bNodeTemplate ntemp;
+
+       ntemp.type = arg->type;
+       ntemp.ngroup = arg->ngroup;
+
+       if(event == UI_NODE_LINK_DISCONNECT)
+               node_socket_disconnect(bmain, ntree, node_to, sock_to);
+       else if(event == UI_NODE_LINK_REMOVE)
+               node_socket_remove(bmain, ntree, node_to, sock_to);
+       else
+               node_socket_add_replace(bmain, ntree, node_to, sock_to, &ntemp, arg->output);
+}
+
+static void ui_node_sock_name(bNodeSocket *sock, char name[UI_MAX_NAME_STR])
+{
+       if(sock->link && sock->link->fromnode) {
+               bNode *node = sock->link->fromnode;
+               char node_name[UI_MAX_NAME_STR];
+
+               if(node->type == NODE_GROUP)
+                       BLI_strncpy(node_name, node->id->name+2, UI_MAX_NAME_STR);
+               else
+                       BLI_strncpy(node_name, node->typeinfo->name, UI_MAX_NAME_STR);
+
+               if(node->inputs.first == NULL &&
+                  node->outputs.first != node->outputs.last &&
+                  !(node->typeinfo->flag & NODE_OPTIONS))
+                       BLI_snprintf(name, UI_MAX_NAME_STR, "%s | %s", node_name, sock->link->fromsock->name);
+               else
+                       BLI_strncpy(name, node_name, UI_MAX_NAME_STR);
+       }
+       else if(sock->type == SOCK_SHADER)
+               BLI_strncpy(name, "None", UI_MAX_NAME_STR);
+       else
+               BLI_strncpy(name, "Default", UI_MAX_NAME_STR);
+}
+
+static int ui_compatible_sockets(int typeA, int typeB)
+{
+       return (typeA == typeB);
+}
+
+static void ui_node_menu_column(NodeLinkArg *arg, int nclass, const char *cname)
+{
+       Main *bmain = arg->bmain;
+       bNodeTree *ntree = arg->ntree;
+       bNodeSocket *sock = arg->sock;
+       uiLayout *layout = arg->layout;
+       uiLayout *column = NULL;
+       uiBlock *block = uiLayoutGetBlock(layout);
+       uiBut *but;
+       bNodeType *ntype;
+       bNodeTree *ngroup;
+       NodeLinkArg *argN;
+       int first = 1;
+       int compatibility= 0;
+
+       if(ntree->type == NTREE_SHADER) {
+               if(scene_use_new_shading_nodes(arg->scene))
+                       compatibility= NODE_NEW_SHADING;
+               else
+                       compatibility= NODE_OLD_SHADING;
+       }
+
+       if(nclass == NODE_CLASS_GROUP) {
+               for(ngroup=bmain->nodetree.first; ngroup; ngroup=ngroup->id.next) {
+                       bNodeSocket *gsock;
+                       char name[UI_MAX_NAME_STR];
+                       int i, j, num = 0;
+
+                       if(ngroup->type != ntree->type)
+                               continue;
+
+                       for(gsock=ngroup->inputs.first; gsock; gsock=gsock->next)
+                               if(ui_compatible_sockets(gsock->type, sock->type))
+                                       num++;
+
+                       for(i=0, j=0, gsock=ngroup->outputs.first; gsock; gsock=gsock->next, i++) {
+                               if(!ui_compatible_sockets(gsock->type, sock->type))
+                                       continue;
+
+                               if(first) {
+                                       column= uiLayoutColumn(layout, 0);
+                                       uiBlockSetCurLayout(block, column);
+
+                                       uiItemL(column, cname, ICON_NODE);
+                                       but= block->buttons.last;
+                                       but->flag= UI_TEXT_LEFT;
+
+                                       first = 0;
+                               }
+
+                               if(num > 1) {
+                                       if(j == 0) {
+                                               uiItemL(column, ngroup->id.name+2, ICON_NODE);
+                                               but= block->buttons.last;
+                                               but->flag= UI_TEXT_LEFT;
+                                       }
+
+                                       BLI_snprintf(name, UI_MAX_NAME_STR, "  %s", gsock->name);
+                                       j++;
+                               }
+                               else
+                                       BLI_strncpy(name, ngroup->id.name+2, UI_MAX_NAME_STR);
+
+                               but = uiDefBut(block, BUT, 0, ngroup->id.name+2, 0, 0, UI_UNIT_X*4, UI_UNIT_Y,
+                                       NULL, 0.0, 0.0, 0.0, 0.0, "Add node to input");
+
+                               argN = MEM_dupallocN(arg);
+                               argN->ngroup = ngroup;
+                               argN->output = i;
+                               uiButSetNFunc(but, ui_node_link, argN, NULL);
+                       }
+               }
+       }
+       else {
+               bNodeTreeType *ttype= ntreeGetType(ntree->type);
+
+               for(ntype=ttype->node_types.first; ntype; ntype=ntype->next) {
+                       bNodeSocketTemplate *stemp;
+                       char name[UI_MAX_NAME_STR];
+                       int i, j, num = 0;
+
+                       if(compatibility && !(ntype->compatibility & compatibility))
+                               continue;
+
+                       if(ntype->nclass != nclass)
+                               continue;
+
+                       for(i=0, stemp=ntype->outputs; stemp && stemp->type != -1; stemp++, i++)
+                               if(ui_compatible_sockets(stemp->type, sock->type))
+                                       num++;
+
+                       for(i=0, j=0, stemp=ntype->outputs; stemp && stemp->type != -1; stemp++, i++) {
+                               if(!ui_compatible_sockets(stemp->type, sock->type))
+                                       continue;
+
+                               if(first) {
+                                       column= uiLayoutColumn(layout, 0);
+                                       uiBlockSetCurLayout(block, column);
+
+                                       uiItemL(column, cname, ICON_NODE);
+                                       but= block->buttons.last;
+                                       but->flag= UI_TEXT_LEFT;
+
+                                       first = 0;
+                               }
+
+                               if(num > 1) {
+                                       if(j == 0) {
+                                               uiItemL(column, ntype->name, ICON_NODE);
+                                               but= block->buttons.last;
+                                               but->flag= UI_TEXT_LEFT;
+                                       }
+
+                                       BLI_snprintf(name, UI_MAX_NAME_STR, "  %s", stemp->name);
+                                       j++;
+                               }
+                               else
+                                       BLI_strncpy(name, ntype->name, UI_MAX_NAME_STR);
+
+                               but = uiDefBut(block, BUT, 0, name, 0, 0, UI_UNIT_X*4, UI_UNIT_Y,
+                                       NULL, 0.0, 0.0, 0.0, 0.0, "Add node to input");
+
+                               argN = MEM_dupallocN(arg);
+                               argN->type = ntype->type;
+                               argN->output = i;
+                               uiButSetNFunc(but, ui_node_link, argN, NULL);
+                       }
+               }
+       }
+}
+
+static void node_menu_column_foreach_cb(void *calldata, int nclass, const char *name)
+{
+       NodeLinkArg *arg = (NodeLinkArg*)calldata;
+
+       if(!ELEM(nclass, NODE_CLASS_GROUP, NODE_CLASS_LAYOUT))
+               ui_node_menu_column(arg, nclass, IFACE_(name));
+}
+
+static void ui_template_node_link_menu(bContext *C, uiLayout *layout, void *but_p)
+{
+       Main *bmain= CTX_data_main(C);
+       Scene *scene= CTX_data_scene(C);
+       uiBlock *block = uiLayoutGetBlock(layout);
+       uiBut *but = (uiBut*)but_p;
+       uiLayout *split, *column;
+       NodeLinkArg *arg = (NodeLinkArg*)but->func_argN;
+       bNodeSocket *sock = arg->sock;
+       bNodeTreeType *ntreetype= ntreeGetType(arg->ntree->type);
+
+       uiBlockSetCurLayout(block, layout);
+       split= uiLayoutSplit(layout, 0, 0);
+
+       arg->bmain= bmain;
+       arg->scene= scene;
+       arg->layout= split;
+       
+       if(ntreetype && ntreetype->foreach_nodeclass)
+               ntreetype->foreach_nodeclass(scene, arg, node_menu_column_foreach_cb);
+
+       column= uiLayoutColumn(split, 0);
+       uiBlockSetCurLayout(block, column);
+
+       if(sock->link) {
+               uiItemL(column, "Link", ICON_NONE);
+               but= block->buttons.last;
+               but->flag= UI_TEXT_LEFT;
+
+               but = uiDefBut(block, BUT, 0, "Remove", 0, 0, UI_UNIT_X*4, UI_UNIT_Y,
+                       NULL, 0.0, 0.0, 0.0, 0.0, "Remove nodes connected to the input");
+               uiButSetNFunc(but, ui_node_link, MEM_dupallocN(arg), SET_INT_IN_POINTER(UI_NODE_LINK_REMOVE));
+
+               but = uiDefBut(block, BUT, 0, "Disconnect", 0, 0, UI_UNIT_X*4, UI_UNIT_Y,
+                       NULL, 0.0, 0.0, 0.0, 0.0, "Disconnect nodes connected to the input");
+               uiButSetNFunc(but, ui_node_link, MEM_dupallocN(arg), SET_INT_IN_POINTER(UI_NODE_LINK_DISCONNECT));
+       }
+
+       ui_node_menu_column(arg, NODE_CLASS_GROUP, IFACE_("Group"));
+}
+
+void uiTemplateNodeLink(uiLayout *layout, bNodeTree *ntree, bNode *node, bNodeSocket *sock)
+{
+       uiBlock *block = uiLayoutGetBlock(layout);
+       NodeLinkArg *arg;
+       uiBut *but;
+
+       arg = MEM_callocN(sizeof(NodeLinkArg), "NodeLinkArg");
+       arg->ntree = ntree;
+       arg->node = node;
+       arg->sock = sock;
+       arg->type = 0;
+       arg->output = 0;
+
+       uiBlockSetCurLayout(block, layout);
+
+       if(sock->link || sock->type == SOCK_SHADER || (sock->flag & SOCK_HIDE_VALUE)) {
+               char name[UI_MAX_NAME_STR];
+               ui_node_sock_name(sock, name);
+               but= uiDefMenuBut(block, ui_template_node_link_menu, NULL, name, 0, 0, UI_UNIT_X*4, UI_UNIT_Y, "");
+       }
+       else
+               but= uiDefIconMenuBut(block, ui_template_node_link_menu, NULL, ICON_NONE, 0, 0, UI_UNIT_X, UI_UNIT_Y, "");
+
+       but->type= MENU;
+       but->flag |= UI_TEXT_LEFT|UI_BUT_NODE_LINK;
+       but->poin= (char*)but;
+       but->func_argN = arg;
+}
+
+/**************************** Node Tree Layout *******************************/
+
+static void ui_node_draw_input(uiLayout *layout, bContext *C,
+       bNodeTree *ntree, bNode *node, bNodeSocket *input, int depth);
+
+static void ui_node_draw_node(uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, int depth)
+{
+       bNodeSocket *input;
+       uiLayout *col, *split;
+       PointerRNA nodeptr;
+
+       RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr);
+
+       if(node->typeinfo->uifunc) {
+               if(node->type != NODE_GROUP) {
+                       split = uiLayoutSplit(layout, 0.35f, 0);
+                       col = uiLayoutColumn(split, 0);
+                       col = uiLayoutColumn(split, 0);
+
+                       node->typeinfo->uifunc(col, C, &nodeptr);
+               }
+       }
+
+       for(input=node->inputs.first; input; input=input->next)
+               ui_node_draw_input(layout, C, ntree, node, input, depth+1);
+}
+
+static void ui_node_draw_input(uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *input, int depth)
+{
+       PointerRNA inputptr;
+       uiBlock *block = uiLayoutGetBlock(layout);
+       uiBut *bt;
+       uiLayout *split, *row, *col;
+       bNode *lnode;
+       char label[UI_MAX_NAME_STR];
+       int indent = (depth > 1)? 2*(depth - 1): 0;
+
+       if(input->flag & SOCK_UNAVAIL)
+               return;
+
+       /* to avoid eternal loops on cyclic dependencies */
+       node->flag |= NODE_TEST;
+       lnode = (input->link)? input->link->fromnode: NULL;
+
+       /* socket RNA pointer */
+       RNA_pointer_create(&ntree->id, &RNA_NodeSocket, input, &inputptr);
+
+       /* indented label */
+       memset(label, ' ', indent);
+       label[indent] = '\0';
+       BLI_snprintf(label, UI_MAX_NAME_STR, "%s%s:", label, input->name);
+
+       /* split in label and value */
+       split = uiLayoutSplit(layout, 0.35f, 0);
+
+       row = uiLayoutRow(split, 1);
+
+       if(depth > 0) {
+               uiBlockSetEmboss(block, UI_EMBOSSN);
+
+               if(lnode && (lnode->inputs.first || (lnode->typeinfo->uifunc && lnode->type != NODE_GROUP))) {
+                       int icon = (input->flag & SOCK_COLLAPSED)? ICON_DISCLOSURE_TRI_RIGHT: ICON_DISCLOSURE_TRI_DOWN;
+                       uiItemR(row, &inputptr, "show_expanded", UI_ITEM_R_ICON_ONLY, "", icon);
+               }
+               else
+                       uiItemL(row, "", ICON_BLANK1);
+
+               bt = block->buttons.last;
+               bt->x2 = UI_UNIT_X/2;
+
+               uiBlockSetEmboss(block, UI_EMBOSS);
+       }
+
+       uiItemL(row, label, ICON_NONE);
+       bt= block->buttons.last;
+       bt->flag= UI_TEXT_LEFT;
+
+       if(lnode) {
+               /* input linked to a node */
+               uiTemplateNodeLink(split, ntree, node, input);
+
+               if(!(input->flag & SOCK_COLLAPSED)) {
+                       if(depth == 0)
+                               uiItemS(layout);
+
+                       ui_node_draw_node(layout, C, ntree, lnode, depth);
+               }
+       }
+       else {
+               /* input not linked, show value */
+               if(input->type != SOCK_SHADER && !(input->flag & SOCK_HIDE_VALUE)) {
+                       if(input->type == SOCK_VECTOR) {
+                               row = uiLayoutRow(split, 0);
+                               col = uiLayoutColumn(row, 0);
+
+                               uiItemR(col, &inputptr, "default_value", 0, "", 0);
+                       }
+                       else {
+                               row = uiLayoutRow(split, 1);
+                               uiItemR(row, &inputptr, "default_value", 0, "", 0);
+                       }
+               }
+               else
+                       row = uiLayoutRow(split, 0);
+
+               uiTemplateNodeLink(row, ntree, node, input);
+       }
+
+       /* clear */
+       node->flag &= ~NODE_TEST;
+}
+
+void uiTemplateNodeView(uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *input)
+{
+       bNode *tnode;
+
+       if(!ntree)
+               return;
+
+       /* clear for cycle check */
+       for(tnode=ntree->nodes.first; tnode; tnode=tnode->next)
+               tnode->flag &= ~NODE_TEST;
+
+       if(input)
+               ui_node_draw_input(layout, C, ntree, node, input, 0);
+       else
+               ui_node_draw_node(layout, C, ntree, node, 0);
+}
+
index a7e7a7b7577b07ac982fe0acab7e9cf9b0d31234..9ff56f1aeb0024b276f3ea96b1891f94c00ff25d 100644 (file)
@@ -448,6 +448,23 @@ void RNA_api_ui_layout(StructRNA *srna)
        func= RNA_def_function(srna, "template_reports_banner", "uiTemplateReportsBanner");
        RNA_def_function_flag(func, FUNC_USE_CONTEXT);
 
+       func= RNA_def_function(srna, "template_node_link", "uiTemplateNodeLink");
+       parm= RNA_def_pointer(func, "ntree", "NodeTree", "", "");
+       RNA_def_property_flag(parm, PROP_REQUIRED);
+       parm= RNA_def_pointer(func, "node", "Node", "", "");
+       RNA_def_property_flag(parm, PROP_REQUIRED);
+       parm= RNA_def_pointer(func, "socket", "NodeSocket", "", "");
+       RNA_def_property_flag(parm, PROP_REQUIRED);
+
+       func= RNA_def_function(srna, "template_node_view", "uiTemplateNodeView");
+       RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+       parm= RNA_def_pointer(func, "ntree", "NodeTree", "", "");
+       RNA_def_property_flag(parm, PROP_REQUIRED);
+       parm= RNA_def_pointer(func, "node", "Node", "", "");
+       RNA_def_property_flag(parm, PROP_REQUIRED);
+       parm= RNA_def_pointer(func, "socket", "NodeSocket", "", "");
+       RNA_def_property_flag(parm, PROP_REQUIRED);
+
        func= RNA_def_function(srna, "template_keymap_item_properties", "uiTemplateKeymapItemProperties");
        parm= RNA_def_pointer(func, "item", "KeyMapItem", "", "");
        RNA_def_property_flag(parm, PROP_REQUIRED|PROP_RNAPTR|PROP_NEVER_NULL);
index 0e489107066408d1b0269ea5d5d4183569da7f6f..4bc7aa4d689aa22f13f4a697b9645d0664ae9a3a 100644 (file)
@@ -41,6 +41,7 @@ struct ARegionType;
 struct Base;
 struct Brush;
 struct bNodeTree;
+struct bNodeSocket;
 struct CSG_FaceIteratorDescriptor;
 struct CSG_VertexIteratorDescriptor;
 struct ColorBand;
@@ -369,6 +370,8 @@ void uiTemplateHistogram(struct uiLayout *layout, struct PointerRNA *ptr, char *
 void uiTemplateReportsBanner(struct uiLayout *layout, struct bContext *C, struct wmOperator *op){}
 void uiTemplateWaveform(struct uiLayout *layout, struct PointerRNA *ptr, char *propname, int expand){}
 void uiTemplateVectorscope(struct uiLayout *_self, struct PointerRNA *data, char* property, int expand){}
+void uiTemplateNodeLink(struct uiLayout *layout, struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *input) {}
+void uiTemplateNodeView(struct uiLayout *layout, struct bContext *C, struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *input) {}
 void uiTemplateKeymapItemProperties(struct uiLayout *layout, struct PointerRNA *ptr){}
 void uiTemplateMovieClip(struct uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, int compact){}
 void uiTemplateTrack(struct uiLayout *layout, struct PointerRNA *ptr, const char *propname){}