UI/Nodes: templates to edit nodes from the properties editor using a tree view,
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.
This commit is contained in:
		| @@ -66,6 +66,9 @@ struct uiWidgetColors; | |||||||
| struct Tex; | struct Tex; | ||||||
| struct MTex; | struct MTex; | ||||||
| struct ImBuf; | struct ImBuf; | ||||||
|  | struct bNodeTree; | ||||||
|  | struct bNode; | ||||||
|  | struct bNodeSocket; | ||||||
|  |  | ||||||
| typedef struct uiBut uiBut; | typedef struct uiBut uiBut; | ||||||
| typedef struct uiBlock uiBlock; | typedef struct uiBlock uiBlock; | ||||||
| @@ -74,6 +77,10 @@ typedef struct uiLayout uiLayout; | |||||||
|  |  | ||||||
| /* Defines */ | /* Defines */ | ||||||
|  |  | ||||||
|  | /* names */ | ||||||
|  | #define UI_MAX_DRAW_STR	400 | ||||||
|  | #define UI_MAX_NAME_STR	128 | ||||||
|  |  | ||||||
| /* uiBlock->dt */ | /* uiBlock->dt */ | ||||||
| #define UI_EMBOSS		0	/* use widget style for drawing */ | #define UI_EMBOSS		0	/* use widget style for drawing */ | ||||||
| #define UI_EMBOSSN		1	/* Nothing, only icon and/or text */ | #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_LEFT	128 | ||||||
| #define UI_ICON_SUBMENU	256 | #define UI_ICON_SUBMENU	256 | ||||||
| #define UI_ICON_PREVIEW	512 | #define UI_ICON_PREVIEW	512 | ||||||
| 	/* control for button type block */ |  | ||||||
| #define UI_MAKE_TOP		1024 | #define UI_TEXT_RIGHT		1024 | ||||||
| #define UI_MAKE_DOWN	2048 | #define UI_BUT_NODE_LINK	2048 | ||||||
| #define UI_MAKE_LEFT	4096 | #define UI_BUT_NODE_ACTIVE	4096 | ||||||
| #define UI_MAKE_RIGHT	8192 | #define UI_FLAG_UNUSED		8192 | ||||||
|  |  | ||||||
| 	/* button align flag, for drawing groups together */ | 	/* 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) | #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 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 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 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); | void uiTemplateTrack(struct uiLayout *layout, struct PointerRNA *ptr, const char *propname); | ||||||
|   | |||||||
| @@ -79,6 +79,7 @@ typedef enum { | |||||||
| 	UI_WTYPE_MENU_RADIO, | 	UI_WTYPE_MENU_RADIO, | ||||||
| 	UI_WTYPE_MENU_ICON_RADIO, | 	UI_WTYPE_MENU_ICON_RADIO, | ||||||
| 	UI_WTYPE_MENU_POINTER_LINK, | 	UI_WTYPE_MENU_POINTER_LINK, | ||||||
|  | 	UI_WTYPE_MENU_NODE_LINK, | ||||||
| 	 | 	 | ||||||
| 	UI_WTYPE_PULLDOWN, | 	UI_WTYPE_PULLDOWN, | ||||||
| 	UI_WTYPE_MENU_ITEM, | 	UI_WTYPE_MENU_ITEM, | ||||||
| @@ -96,11 +97,6 @@ typedef enum { | |||||||
| 	 | 	 | ||||||
| } uiWidgetTypeEnum; | } uiWidgetTypeEnum; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #define UI_MAX_DRAW_STR	400 |  | ||||||
| #define UI_MAX_NAME_STR	128 |  | ||||||
|  |  | ||||||
| /* panel limits */ | /* panel limits */ | ||||||
| #define UI_PANEL_MINX	100 | #define UI_PANEL_MINX	100 | ||||||
| #define UI_PANEL_MINY	70 | #define UI_PANEL_MINY	70 | ||||||
|   | |||||||
| @@ -1533,15 +1533,6 @@ uiPopupBlockHandle *ui_popup_block_create(bContext *C, ARegion *butregion, uiBut | |||||||
| 		if(ELEM(but->type, BLOCK, PULLDOWN)) | 		if(ELEM(but->type, BLOCK, PULLDOWN)) | ||||||
| 			block->xofs = -2;	/* for proper alignment */ | 			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); | 		ui_block_position(window, butregion, but, block); | ||||||
| 	} | 	} | ||||||
| 	else { | 	else { | ||||||
|   | |||||||
| @@ -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); | 			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 | 		/* If there's an icon too (made with uiDefIconTextBut) then draw the icon | ||||||
| 		and offset the text label to accommodate it */ | 		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}; | 		char red[4]= {255, 0, 0}; | ||||||
| 		widget_state_blend(wt->wcol.inner, red, 0.4f); | 		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 */ | /* 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); | 	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)) | static void widget_pulldownbut(uiWidgetColors *wcol, rcti *rect, int state, int UNUSED(roundboxalign)) | ||||||
| { | { | ||||||
| 	if(state & UI_ACTIVE) { | 	if(state & UI_ACTIVE) { | ||||||
| @@ -2804,6 +2837,11 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type) | |||||||
| 			wt.wcol_theme= &btheme->tui.wcol_menu; | 			wt.wcol_theme= &btheme->tui.wcol_menu; | ||||||
| 			wt.draw= widget_menubut; | 			wt.draw= widget_menubut; | ||||||
| 			break; | 			break; | ||||||
|  |  | ||||||
|  | 		case UI_WTYPE_MENU_NODE_LINK: | ||||||
|  | 			wt.wcol_theme= &btheme->tui.wcol_menu; | ||||||
|  | 			wt.draw= widget_menunodebut; | ||||||
|  | 			break; | ||||||
| 			 | 			 | ||||||
| 		case UI_WTYPE_PULLDOWN: | 		case UI_WTYPE_PULLDOWN: | ||||||
| 			wt.wcol_theme= &btheme->tui.wcol_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 MENU: | ||||||
| 			case BLOCK: | 			case BLOCK: | ||||||
| 			case ICONTEXTROW: | 			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); | 					wt= widget_type(UI_WTYPE_MENU_ICON_RADIO); | ||||||
| 				else | 				else | ||||||
| 					wt= widget_type(UI_WTYPE_MENU_RADIO); | 					wt= widget_type(UI_WTYPE_MENU_RADIO); | ||||||
|   | |||||||
| @@ -47,6 +47,7 @@ set(SRC | |||||||
| 	node_ops.c | 	node_ops.c | ||||||
| 	node_select.c | 	node_select.c | ||||||
| 	node_state.c | 	node_state.c | ||||||
|  | 	node_templates.c | ||||||
| 	space_node.c | 	space_node.c | ||||||
|  |  | ||||||
| 	node_intern.h | 	node_intern.h | ||||||
|   | |||||||
| @@ -45,6 +45,7 @@ | |||||||
| #include "BLI_utildefines.h" | #include "BLI_utildefines.h" | ||||||
|  |  | ||||||
| #include "BKE_context.h" | #include "BKE_context.h" | ||||||
|  | #include "BKE_global.h" | ||||||
| #include "BKE_node.h" | #include "BKE_node.h" | ||||||
| #include "BKE_screen.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); | 		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 ************** */ | /* ******************* node buttons registration ************** */ | ||||||
|  |  | ||||||
| void node_buttons_register(ARegionType *art) | void node_buttons_register(ARegionType *art) | ||||||
| @@ -134,6 +163,14 @@ void node_buttons_register(ARegionType *art) | |||||||
| 	pt->draw= active_node_panel; | 	pt->draw= active_node_panel; | ||||||
| 	pt->poll= active_node_poll; | 	pt->poll= active_node_poll; | ||||||
| 	BLI_addtail(&art->paneltypes, pt); | 	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"); | 	pt= MEM_callocN(sizeof(PanelType), "spacetype node panel gpencil"); | ||||||
| 	strcpy(pt->idname, "NODE_PT_gpencil"); | 	strcpy(pt->idname, "NODE_PT_gpencil"); | ||||||
|   | |||||||
							
								
								
									
										636
									
								
								source/blender/editors/space_node/node_templates.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										636
									
								
								source/blender/editors/space_node/node_templates.c
									
									
									
									
									
										Normal file
									
								
							| @@ -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); | ||||||
|  | } | ||||||
|  |  | ||||||
| @@ -448,6 +448,23 @@ void RNA_api_ui_layout(StructRNA *srna) | |||||||
| 	func= RNA_def_function(srna, "template_reports_banner", "uiTemplateReportsBanner"); | 	func= RNA_def_function(srna, "template_reports_banner", "uiTemplateReportsBanner"); | ||||||
| 	RNA_def_function_flag(func, FUNC_USE_CONTEXT); | 	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"); | 	func= RNA_def_function(srna, "template_keymap_item_properties", "uiTemplateKeymapItemProperties"); | ||||||
| 	parm= RNA_def_pointer(func, "item", "KeyMapItem", "", ""); | 	parm= RNA_def_pointer(func, "item", "KeyMapItem", "", ""); | ||||||
| 	RNA_def_property_flag(parm, PROP_REQUIRED|PROP_RNAPTR|PROP_NEVER_NULL); | 	RNA_def_property_flag(parm, PROP_REQUIRED|PROP_RNAPTR|PROP_NEVER_NULL); | ||||||
|   | |||||||
| @@ -41,6 +41,7 @@ struct ARegionType; | |||||||
| struct Base; | struct Base; | ||||||
| struct Brush; | struct Brush; | ||||||
| struct bNodeTree; | struct bNodeTree; | ||||||
|  | struct bNodeSocket; | ||||||
| struct CSG_FaceIteratorDescriptor; | struct CSG_FaceIteratorDescriptor; | ||||||
| struct CSG_VertexIteratorDescriptor; | struct CSG_VertexIteratorDescriptor; | ||||||
| struct ColorBand; | 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 uiTemplateReportsBanner(struct uiLayout *layout, struct bContext *C, struct wmOperator *op){} | ||||||
| void uiTemplateWaveform(struct uiLayout *layout, struct PointerRNA *ptr, char *propname, int expand){} | 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 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 uiTemplateKeymapItemProperties(struct uiLayout *layout, struct PointerRNA *ptr){} | ||||||
| void uiTemplateMovieClip(struct uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, int compact){} | 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){} | void uiTemplateTrack(struct uiLayout *layout, struct PointerRNA *ptr, const char *propname){} | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user